gimli/read/
cfi.rs

1#[cfg(feature = "read")]
2use alloc::boxed::Box;
3
4use core::cmp::Ordering;
5use core::fmt::{self, Debug};
6use core::iter::FromIterator;
7use core::mem;
8use core::num::Wrapping;
9
10use super::util::{ArrayLike, ArrayVec};
11use crate::common::{
12    DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor,
13};
14use crate::constants::{self, DwEhPe};
15use crate::endianity::Endianity;
16use crate::read::{
17    EndianSlice, Error, Expression, Reader, ReaderAddress, ReaderOffset, Result, Section,
18    StoreOnHeap,
19};
20
21/// `DebugFrame` contains the `.debug_frame` section's frame unwinding
22/// information required to unwind to and recover registers from older frames on
23/// the stack. For example, this is useful for a debugger that wants to print
24/// locals in a backtrace.
25///
26/// Most interesting methods are defined in the
27/// [`UnwindSection`](trait.UnwindSection.html) trait.
28///
29/// ### Differences between `.debug_frame` and `.eh_frame`
30///
31/// While the `.debug_frame` section's information has a lot of overlap with the
32/// `.eh_frame` section's information, the `.eh_frame` information tends to only
33/// encode the subset of information needed for exception handling. Often, only
34/// one of `.eh_frame` or `.debug_frame` will be present in an object file.
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct DebugFrame<R: Reader> {
37    section: R,
38    address_size: u8,
39    vendor: Vendor,
40}
41
42impl<R: Reader> DebugFrame<R> {
43    /// Set the size of a target address in bytes.
44    ///
45    /// This defaults to the native word size.
46    /// This is only used if the CIE version is less than 4.
47    pub fn set_address_size(&mut self, address_size: u8) {
48        self.address_size = address_size
49    }
50
51    /// Set the vendor extensions to use.
52    ///
53    /// This defaults to `Vendor::Default`.
54    pub fn set_vendor(&mut self, vendor: Vendor) {
55        self.vendor = vendor;
56    }
57}
58
59impl<'input, Endian> DebugFrame<EndianSlice<'input, Endian>>
60where
61    Endian: Endianity,
62{
63    /// Construct a new `DebugFrame` instance from the data in the
64    /// `.debug_frame` section.
65    ///
66    /// It is the caller's responsibility to read the section and present it as
67    /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O
68    /// loader on macOS, etc.
69    ///
70    /// ```
71    /// use gimli::{DebugFrame, NativeEndian};
72    ///
73    /// // Use with `.debug_frame`
74    /// # let buf = [0x00, 0x01, 0x02, 0x03];
75    /// # let read_debug_frame_section_somehow = || &buf;
76    /// let debug_frame = DebugFrame::new(read_debug_frame_section_somehow(), NativeEndian);
77    /// ```
78    pub fn new(section: &'input [u8], endian: Endian) -> Self {
79        Self::from(EndianSlice::new(section, endian))
80    }
81}
82
83impl<R: Reader> Section<R> for DebugFrame<R> {
84    fn id() -> SectionId {
85        SectionId::DebugFrame
86    }
87
88    fn reader(&self) -> &R {
89        &self.section
90    }
91}
92
93impl<R: Reader> From<R> for DebugFrame<R> {
94    fn from(section: R) -> Self {
95        // Default to native word size.
96        DebugFrame {
97            section,
98            address_size: mem::size_of::<usize>() as u8,
99            vendor: Vendor::Default,
100        }
101    }
102}
103
104/// `EhFrameHdr` contains the information about the `.eh_frame_hdr` section.
105///
106/// A pointer to the start of the `.eh_frame` data, and optionally, a binary
107/// search table of pointers to the `.eh_frame` records that are found in this section.
108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109pub struct EhFrameHdr<R: Reader>(R);
110
111/// `ParsedEhFrameHdr` contains the parsed information from the `.eh_frame_hdr` section.
112#[derive(Clone, Debug)]
113pub struct ParsedEhFrameHdr<R: Reader> {
114    address_size: u8,
115    section: R,
116
117    eh_frame_ptr: Pointer,
118    fde_count: u64,
119    table_enc: DwEhPe,
120    table: R,
121}
122
123impl<'input, Endian> EhFrameHdr<EndianSlice<'input, Endian>>
124where
125    Endian: Endianity,
126{
127    /// Constructs a new `EhFrameHdr` instance from the data in the `.eh_frame_hdr` section.
128    pub fn new(section: &'input [u8], endian: Endian) -> Self {
129        Self::from(EndianSlice::new(section, endian))
130    }
131}
132
133impl<R: Reader> EhFrameHdr<R> {
134    /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`.
135    pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result<ParsedEhFrameHdr<R>> {
136        let mut reader = self.0.clone();
137        let version = reader.read_u8()?;
138        if version != 1 {
139            return Err(Error::UnknownVersion(u64::from(version)));
140        }
141
142        let eh_frame_ptr_enc = parse_pointer_encoding(&mut reader)?;
143        let fde_count_enc = parse_pointer_encoding(&mut reader)?;
144        let table_enc = parse_pointer_encoding(&mut reader)?;
145
146        let parameters = PointerEncodingParameters {
147            bases: &bases.eh_frame_hdr,
148            func_base: None,
149            address_size,
150            section: &self.0,
151        };
152
153        // Omitting this pointer is not valid (defeats the purpose of .eh_frame_hdr entirely)
154        if eh_frame_ptr_enc == constants::DW_EH_PE_omit {
155            return Err(Error::CannotParseOmitPointerEncoding);
156        }
157        let eh_frame_ptr = parse_encoded_pointer(eh_frame_ptr_enc, &parameters, &mut reader)?;
158
159        let fde_count;
160        if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit {
161            fde_count = 0
162        } else {
163            if fde_count_enc != fde_count_enc.format() {
164                return Err(Error::UnsupportedPointerEncoding);
165            }
166            fde_count = parse_encoded_value(fde_count_enc, &parameters, &mut reader)?;
167        }
168
169        Ok(ParsedEhFrameHdr {
170            address_size,
171            section: self.0.clone(),
172
173            eh_frame_ptr,
174            fde_count,
175            table_enc,
176            table: reader,
177        })
178    }
179}
180
181impl<R: Reader> Section<R> for EhFrameHdr<R> {
182    fn id() -> SectionId {
183        SectionId::EhFrameHdr
184    }
185
186    fn reader(&self) -> &R {
187        &self.0
188    }
189}
190
191impl<R: Reader> From<R> for EhFrameHdr<R> {
192    fn from(section: R) -> Self {
193        EhFrameHdr(section)
194    }
195}
196
197impl<R: Reader> ParsedEhFrameHdr<R> {
198    /// Returns the address of the binary's `.eh_frame` section.
199    pub fn eh_frame_ptr(&self) -> Pointer {
200        self.eh_frame_ptr
201    }
202
203    /// Retrieves the CFI binary search table, if there is one.
204    pub fn table(&self) -> Option<EhHdrTable<'_, R>> {
205        // There are two big edge cases here:
206        // * You search the table for an invalid address. As this is just a binary
207        //   search table, we always have to return a valid result for that (unless
208        //   you specify an address that is lower than the first address in the
209        //   table). Since this means that you have to recheck that the FDE contains
210        //   your address anyways, we just return the first FDE even when the address
211        //   is too low. After all, we're just doing a normal binary search.
212        // * This falls apart when the table is empty - there is no entry we could
213        //   return. We conclude that an empty table is not really a table at all.
214        if self.fde_count == 0 {
215            None
216        } else {
217            Some(EhHdrTable { hdr: self })
218        }
219    }
220}
221
222/// An iterator for `.eh_frame_hdr` section's binary search table.
223///
224/// Each table entry consists of a tuple containing an  `initial_location` and `address`.
225/// The `initial location` represents the first address that the targeted FDE
226/// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section.
227/// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE.
228#[derive(Debug)]
229pub struct EhHdrTableIter<'a, 'bases, R: Reader> {
230    hdr: &'a ParsedEhFrameHdr<R>,
231    table: R,
232    bases: &'bases BaseAddresses,
233    remain: u64,
234}
235
236impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> {
237    /// Yield the next entry in the `EhHdrTableIter`.
238    pub fn next(&mut self) -> Result<Option<(Pointer, Pointer)>> {
239        if self.remain == 0 {
240            return Ok(None);
241        }
242
243        let parameters = PointerEncodingParameters {
244            bases: &self.bases.eh_frame_hdr,
245            func_base: None,
246            address_size: self.hdr.address_size,
247            section: &self.hdr.section,
248        };
249
250        self.remain -= 1;
251        let from = parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut self.table)?;
252        let to = parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut self.table)?;
253        Ok(Some((from, to)))
254    }
255    /// Yield the nth entry in the `EhHdrTableIter`
256    pub fn nth(&mut self, n: usize) -> Result<Option<(Pointer, Pointer)>> {
257        use core::convert::TryFrom;
258        let size = match self.hdr.table_enc.format() {
259            constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
260                return Err(Error::VariableLengthSearchTable);
261            }
262            constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
263            constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
264            constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8,
265            _ => return Err(Error::UnknownPointerEncoding(self.hdr.table_enc)),
266        };
267
268        let row_size = size * 2;
269        let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?;
270        self.remain = self.remain.saturating_sub(n);
271        self.table.skip(R::Offset::from_u64(n * row_size)?)?;
272        self.next()
273    }
274}
275
276#[cfg(feature = "fallible-iterator")]
277impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> {
278    type Item = (Pointer, Pointer);
279    type Error = Error;
280    fn next(&mut self) -> Result<Option<Self::Item>> {
281        EhHdrTableIter::next(self)
282    }
283
284    fn size_hint(&self) -> (usize, Option<usize>) {
285        use core::convert::TryInto;
286        (
287            self.remain.try_into().unwrap_or(0),
288            self.remain.try_into().ok(),
289        )
290    }
291
292    fn nth(&mut self, n: usize) -> Result<Option<Self::Item>> {
293        EhHdrTableIter::nth(self, n)
294    }
295}
296
297/// The CFI binary search table that is an optional part of the `.eh_frame_hdr` section.
298#[derive(Debug, Clone)]
299pub struct EhHdrTable<'a, R: Reader> {
300    hdr: &'a ParsedEhFrameHdr<R>,
301}
302
303impl<'a, R: Reader + 'a> EhHdrTable<'a, R> {
304    /// Return an iterator that can walk the `.eh_frame_hdr` table.
305    ///
306    /// Each table entry consists of a tuple containing an `initial_location` and `address`.
307    /// The `initial location` represents the first address that the targeted FDE
308    /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section.
309    /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE.
310    pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> {
311        EhHdrTableIter {
312            hdr: self.hdr,
313            bases,
314            remain: self.hdr.fde_count,
315            table: self.hdr.table.clone(),
316        }
317    }
318    /// *Probably* returns a pointer to the FDE for the given address.
319    ///
320    /// This performs a binary search, so if there is no FDE for the given address,
321    /// this function **will** return a pointer to any other FDE that's close by.
322    ///
323    /// To be sure, you **must** call `contains` on the FDE.
324    pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result<Pointer> {
325        let size = match self.hdr.table_enc.format() {
326            constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
327                return Err(Error::VariableLengthSearchTable);
328            }
329            constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
330            constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
331            constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8,
332            _ => return Err(Error::UnknownPointerEncoding(self.hdr.table_enc)),
333        };
334
335        let row_size = size * 2;
336
337        let mut len = self.hdr.fde_count;
338
339        let mut reader = self.hdr.table.clone();
340
341        let parameters = PointerEncodingParameters {
342            bases: &bases.eh_frame_hdr,
343            func_base: None,
344            address_size: self.hdr.address_size,
345            section: &self.hdr.section,
346        };
347
348        while len > 1 {
349            let head = reader.split(R::Offset::from_u64((len / 2) * row_size)?)?;
350            let tail = reader.clone();
351
352            let pivot =
353                parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut reader)?.direct()?;
354
355            match pivot.cmp(&address) {
356                Ordering::Equal => {
357                    reader = tail;
358                    break;
359                }
360                Ordering::Less => {
361                    reader = tail;
362                    len = len - (len / 2);
363                }
364                Ordering::Greater => {
365                    reader = head;
366                    len /= 2;
367                }
368            }
369        }
370
371        reader.skip(R::Offset::from_u64(size)?)?;
372
373        parse_encoded_pointer(self.hdr.table_enc, &parameters, &mut reader)
374    }
375
376    /// Convert a `Pointer` to a section offset.
377    ///
378    /// This does not support indirect pointers.
379    pub fn pointer_to_offset(&self, ptr: Pointer) -> Result<EhFrameOffset<R::Offset>> {
380        let ptr = ptr.direct()?;
381        let eh_frame_ptr = self.hdr.eh_frame_ptr().direct()?;
382
383        // Calculate the offset in the EhFrame section
384        R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset)
385    }
386
387    /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress`
388    /// if there are none.
389    ///
390    /// You must provide a function to get its associated CIE. See
391    /// `PartialFrameDescriptionEntry::parse` for more information.
392    ///
393    /// # Example
394    ///
395    /// ```
396    /// # use gimli::{BaseAddresses, EhFrame, ParsedEhFrameHdr, EndianSlice, NativeEndian, Error, UnwindSection};
397    /// # fn foo() -> Result<(), Error> {
398    /// # let eh_frame: EhFrame<EndianSlice<NativeEndian>> = unreachable!();
399    /// # let eh_frame_hdr: ParsedEhFrameHdr<EndianSlice<NativeEndian>> = unimplemented!();
400    /// # let addr = 0;
401    /// # let bases = unimplemented!();
402    /// let table = eh_frame_hdr.table().unwrap();
403    /// let fde = table.fde_for_address(&eh_frame, &bases, addr, EhFrame::cie_from_offset)?;
404    /// # Ok(())
405    /// # }
406    /// ```
407    pub fn fde_for_address<F>(
408        &self,
409        frame: &EhFrame<R>,
410        bases: &BaseAddresses,
411        address: u64,
412        get_cie: F,
413    ) -> Result<FrameDescriptionEntry<R>>
414    where
415        F: FnMut(
416            &EhFrame<R>,
417            &BaseAddresses,
418            EhFrameOffset<R::Offset>,
419        ) -> Result<CommonInformationEntry<R>>,
420    {
421        let fdeptr = self.lookup(address, bases)?;
422        let offset = self.pointer_to_offset(fdeptr)?;
423        let entry = frame.fde_from_offset(bases, offset, get_cie)?;
424        if entry.contains(address) {
425            Ok(entry)
426        } else {
427            Err(Error::NoUnwindInfoForAddress)
428        }
429    }
430
431    #[inline]
432    #[doc(hidden)]
433    #[deprecated(note = "Method renamed to fde_for_address; use that instead.")]
434    pub fn lookup_and_parse<F>(
435        &self,
436        address: u64,
437        bases: &BaseAddresses,
438        frame: EhFrame<R>,
439        get_cie: F,
440    ) -> Result<FrameDescriptionEntry<R>>
441    where
442        F: FnMut(
443            &EhFrame<R>,
444            &BaseAddresses,
445            EhFrameOffset<R::Offset>,
446        ) -> Result<CommonInformationEntry<R>>,
447    {
448        self.fde_for_address(&frame, bases, address, get_cie)
449    }
450
451    /// Returns the frame unwind information for the given address,
452    /// or `NoUnwindInfoForAddress` if there are none.
453    ///
454    /// You must provide a function to get the associated CIE. See
455    /// `PartialFrameDescriptionEntry::parse` for more information.
456    pub fn unwind_info_for_address<'ctx, F, S>(
457        &self,
458        frame: &EhFrame<R>,
459        bases: &BaseAddresses,
460        ctx: &'ctx mut UnwindContext<R::Offset, S>,
461        address: u64,
462        get_cie: F,
463    ) -> Result<&'ctx UnwindTableRow<R::Offset, S>>
464    where
465        F: FnMut(
466            &EhFrame<R>,
467            &BaseAddresses,
468            EhFrameOffset<R::Offset>,
469        ) -> Result<CommonInformationEntry<R>>,
470        S: UnwindContextStorage<R::Offset>,
471    {
472        let fde = self.fde_for_address(frame, bases, address, get_cie)?;
473        fde.unwind_info_for_address(frame, bases, ctx, address)
474    }
475}
476
477/// `EhFrame` contains the frame unwinding information needed during exception
478/// handling found in the `.eh_frame` section.
479///
480/// Most interesting methods are defined in the
481/// [`UnwindSection`](trait.UnwindSection.html) trait.
482///
483/// See
484/// [`DebugFrame`](./struct.DebugFrame.html#differences-between-debug_frame-and-eh_frame)
485/// for some discussion on the differences between `.debug_frame` and
486/// `.eh_frame`.
487#[derive(Clone, Copy, Debug, PartialEq, Eq)]
488pub struct EhFrame<R: Reader> {
489    section: R,
490    address_size: u8,
491    vendor: Vendor,
492}
493
494impl<R: Reader> EhFrame<R> {
495    /// Set the size of a target address in bytes.
496    ///
497    /// This defaults to the native word size.
498    pub fn set_address_size(&mut self, address_size: u8) {
499        self.address_size = address_size
500    }
501
502    /// Set the vendor extensions to use.
503    ///
504    /// This defaults to `Vendor::Default`.
505    pub fn set_vendor(&mut self, vendor: Vendor) {
506        self.vendor = vendor;
507    }
508}
509
510impl<'input, Endian> EhFrame<EndianSlice<'input, Endian>>
511where
512    Endian: Endianity,
513{
514    /// Construct a new `EhFrame` instance from the data in the
515    /// `.eh_frame` section.
516    ///
517    /// It is the caller's responsibility to read the section and present it as
518    /// a `&[u8]` slice. That means using some ELF loader on Linux, a Mach-O
519    /// loader on macOS, etc.
520    ///
521    /// ```
522    /// use gimli::{EhFrame, EndianSlice, NativeEndian};
523    ///
524    /// // Use with `.eh_frame`
525    /// # let buf = [0x00, 0x01, 0x02, 0x03];
526    /// # let read_eh_frame_section_somehow = || &buf;
527    /// let eh_frame = EhFrame::new(read_eh_frame_section_somehow(), NativeEndian);
528    /// ```
529    pub fn new(section: &'input [u8], endian: Endian) -> Self {
530        Self::from(EndianSlice::new(section, endian))
531    }
532}
533
534impl<R: Reader> Section<R> for EhFrame<R> {
535    fn id() -> SectionId {
536        SectionId::EhFrame
537    }
538
539    fn reader(&self) -> &R {
540        &self.section
541    }
542}
543
544impl<R: Reader> From<R> for EhFrame<R> {
545    fn from(section: R) -> Self {
546        // Default to native word size.
547        EhFrame {
548            section,
549            address_size: mem::size_of::<usize>() as u8,
550            vendor: Vendor::Default,
551        }
552    }
553}
554
555// This has to be `pub` to silence a warning (that is deny(..)'d by default) in
556// rustc. Eventually, not having this `pub` will become a hard error.
557#[doc(hidden)]
558#[allow(missing_docs)]
559#[derive(Clone, Copy, Debug, PartialEq, Eq)]
560pub enum CieOffsetEncoding {
561    U32,
562    U64,
563}
564
565/// An offset into an `UnwindSection`.
566//
567// Needed to avoid conflicting implementations of `Into<T>`.
568pub trait UnwindOffset<T = usize>: Copy + Debug + Eq + From<T>
569where
570    T: ReaderOffset,
571{
572    /// Convert an `UnwindOffset<T>` into a `T`.
573    fn into(self) -> T;
574}
575
576impl<T> UnwindOffset<T> for DebugFrameOffset<T>
577where
578    T: ReaderOffset,
579{
580    #[inline]
581    fn into(self) -> T {
582        self.0
583    }
584}
585
586impl<T> UnwindOffset<T> for EhFrameOffset<T>
587where
588    T: ReaderOffset,
589{
590    #[inline]
591    fn into(self) -> T {
592        self.0
593    }
594}
595
596/// This trait completely encapsulates everything that is different between
597/// `.eh_frame` and `.debug_frame`, as well as all the bits that can change
598/// between DWARF versions.
599#[doc(hidden)]
600pub trait _UnwindSectionPrivate<R: Reader> {
601    /// Get the underlying section data.
602    fn section(&self) -> &R;
603
604    /// Returns true if the section allows a zero terminator.
605    fn has_zero_terminator() -> bool;
606
607    /// Return true if the given offset if the CIE sentinel, false otherwise.
608    fn is_cie(format: Format, id: u64) -> bool;
609
610    /// Return the CIE offset/ID encoding used by this unwind section with the
611    /// given DWARF format.
612    fn cie_offset_encoding(format: Format) -> CieOffsetEncoding;
613
614    /// For `.eh_frame`, CIE offsets are relative to the current position. For
615    /// `.debug_frame`, they are relative to the start of the section. We always
616    /// internally store them relative to the section, so we handle translating
617    /// `.eh_frame`'s relative offsets in this method. If the offset calculation
618    /// underflows, return `None`.
619    fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset>;
620
621    /// Does this version of this unwind section encode address and segment
622    /// sizes in its CIEs?
623    fn has_address_and_segment_sizes(version: u8) -> bool;
624
625    /// The address size to use if `has_address_and_segment_sizes` returns false.
626    fn address_size(&self) -> u8;
627
628    /// The vendor extensions to use.
629    fn vendor(&self) -> Vendor;
630}
631
632/// A section holding unwind information: either `.debug_frame` or
633/// `.eh_frame`. See [`DebugFrame`](./struct.DebugFrame.html) and
634/// [`EhFrame`](./struct.EhFrame.html) respectively.
635pub trait UnwindSection<R: Reader>: Clone + Debug + _UnwindSectionPrivate<R> {
636    /// The offset type associated with this CFI section. Either
637    /// `DebugFrameOffset` or `EhFrameOffset`.
638    type Offset: UnwindOffset<R::Offset>;
639
640    /// Iterate over the `CommonInformationEntry`s and `FrameDescriptionEntry`s
641    /// in this `.debug_frame` section.
642    ///
643    /// Can be [used with
644    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
645    fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> {
646        CfiEntriesIter {
647            section: self.clone(),
648            bases,
649            input: self.section().clone(),
650        }
651    }
652
653    /// Parse the `CommonInformationEntry` at the given offset.
654    fn cie_from_offset(
655        &self,
656        bases: &BaseAddresses,
657        offset: Self::Offset,
658    ) -> Result<CommonInformationEntry<R>> {
659        let offset = UnwindOffset::into(offset);
660        let input = &mut self.section().clone();
661        input.skip(offset)?;
662        CommonInformationEntry::parse(bases, self, input)
663    }
664
665    /// Parse the `PartialFrameDescriptionEntry` at the given offset.
666    fn partial_fde_from_offset<'bases>(
667        &self,
668        bases: &'bases BaseAddresses,
669        offset: Self::Offset,
670    ) -> Result<PartialFrameDescriptionEntry<'bases, Self, R>> {
671        let offset = UnwindOffset::into(offset);
672        let input = &mut self.section().clone();
673        input.skip(offset)?;
674        PartialFrameDescriptionEntry::parse_partial(self, bases, input)
675    }
676
677    /// Parse the `FrameDescriptionEntry` at the given offset.
678    fn fde_from_offset<F>(
679        &self,
680        bases: &BaseAddresses,
681        offset: Self::Offset,
682        get_cie: F,
683    ) -> Result<FrameDescriptionEntry<R>>
684    where
685        F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
686    {
687        let partial = self.partial_fde_from_offset(bases, offset)?;
688        partial.parse(get_cie)
689    }
690
691    /// Find the `FrameDescriptionEntry` for the given address.
692    ///
693    /// If found, the FDE is returned.  If not found,
694    /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned.
695    /// If parsing fails, the error is returned.
696    ///
697    /// You must provide a function to get its associated CIE. See
698    /// `PartialFrameDescriptionEntry::parse` for more information.
699    ///
700    /// Note: this iterates over all FDEs. If available, it is possible
701    /// to do a binary search with `EhFrameHdr::fde_for_address` instead.
702    fn fde_for_address<F>(
703        &self,
704        bases: &BaseAddresses,
705        address: u64,
706        mut get_cie: F,
707    ) -> Result<FrameDescriptionEntry<R>>
708    where
709        F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
710    {
711        let mut entries = self.entries(bases);
712        while let Some(entry) = entries.next()? {
713            match entry {
714                CieOrFde::Cie(_) => {}
715                CieOrFde::Fde(partial) => {
716                    let fde = partial.parse(&mut get_cie)?;
717                    if fde.contains(address) {
718                        return Ok(fde);
719                    }
720                }
721            }
722        }
723        Err(Error::NoUnwindInfoForAddress)
724    }
725
726    /// Find the frame unwind information for the given address.
727    ///
728    /// If found, the unwind information is returned.  If not found,
729    /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or
730    /// CFI evaluation fails, the error is returned.
731    ///
732    /// ```
733    /// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindContext,
734    ///             UnwindSection};
735    ///
736    /// # fn foo() -> gimli::Result<()> {
737    /// # let read_eh_frame_section = || unimplemented!();
738    /// // Get the `.eh_frame` section from the object file. Alternatively,
739    /// // use `EhFrame` with the `.eh_frame` section of the object file.
740    /// let eh_frame = EhFrame::new(read_eh_frame_section(), NativeEndian);
741    ///
742    /// # let get_frame_pc = || unimplemented!();
743    /// // Get the address of the PC for a frame you'd like to unwind.
744    /// let address = get_frame_pc();
745    ///
746    /// // This context is reusable, which cuts down on heap allocations.
747    /// let ctx = UnwindContext::new();
748    ///
749    /// // Optionally provide base addresses for any relative pointers. If a
750    /// // base address isn't provided and a pointer is found that is relative to
751    /// // it, we will return an `Err`.
752    /// # let address_of_text_section_in_memory = unimplemented!();
753    /// # let address_of_got_section_in_memory = unimplemented!();
754    /// let bases = BaseAddresses::default()
755    ///     .set_text(address_of_text_section_in_memory)
756    ///     .set_got(address_of_got_section_in_memory);
757    ///
758    /// let unwind_info = eh_frame.unwind_info_for_address(
759    ///     &bases,
760    ///     &mut ctx,
761    ///     address,
762    ///     EhFrame::cie_from_offset,
763    /// )?;
764    ///
765    /// # let do_stuff_with = |_| unimplemented!();
766    /// do_stuff_with(unwind_info);
767    /// # let _ = ctx;
768    /// # unreachable!()
769    /// # }
770    /// ```
771    #[inline]
772    fn unwind_info_for_address<'ctx, F, S>(
773        &self,
774        bases: &BaseAddresses,
775        ctx: &'ctx mut UnwindContext<R::Offset, S>,
776        address: u64,
777        get_cie: F,
778    ) -> Result<&'ctx UnwindTableRow<R::Offset, S>>
779    where
780        F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
781        S: UnwindContextStorage<R::Offset>,
782    {
783        let fde = self.fde_for_address(bases, address, get_cie)?;
784        fde.unwind_info_for_address(self, bases, ctx, address)
785    }
786}
787
788impl<R: Reader> _UnwindSectionPrivate<R> for DebugFrame<R> {
789    fn section(&self) -> &R {
790        &self.section
791    }
792
793    fn has_zero_terminator() -> bool {
794        false
795    }
796
797    fn is_cie(format: Format, id: u64) -> bool {
798        match format {
799            Format::Dwarf32 => id == 0xffff_ffff,
800            Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff,
801        }
802    }
803
804    fn cie_offset_encoding(format: Format) -> CieOffsetEncoding {
805        match format {
806            Format::Dwarf32 => CieOffsetEncoding::U32,
807            Format::Dwarf64 => CieOffsetEncoding::U64,
808        }
809    }
810
811    fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option<R::Offset> {
812        Some(offset)
813    }
814
815    fn has_address_and_segment_sizes(version: u8) -> bool {
816        version == 4
817    }
818
819    fn address_size(&self) -> u8 {
820        self.address_size
821    }
822
823    fn vendor(&self) -> Vendor {
824        self.vendor
825    }
826}
827
828impl<R: Reader> UnwindSection<R> for DebugFrame<R> {
829    type Offset = DebugFrameOffset<R::Offset>;
830}
831
832impl<R: Reader> _UnwindSectionPrivate<R> for EhFrame<R> {
833    fn section(&self) -> &R {
834        &self.section
835    }
836
837    fn has_zero_terminator() -> bool {
838        true
839    }
840
841    fn is_cie(_: Format, id: u64) -> bool {
842        id == 0
843    }
844
845    fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding {
846        // `.eh_frame` offsets are always 4 bytes, regardless of the DWARF
847        // format.
848        CieOffsetEncoding::U32
849    }
850
851    fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset> {
852        base.checked_sub(offset)
853    }
854
855    fn has_address_and_segment_sizes(_version: u8) -> bool {
856        false
857    }
858
859    fn address_size(&self) -> u8 {
860        self.address_size
861    }
862
863    fn vendor(&self) -> Vendor {
864        self.vendor
865    }
866}
867
868impl<R: Reader> UnwindSection<R> for EhFrame<R> {
869    type Offset = EhFrameOffset<R::Offset>;
870}
871
872/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers.
873///
874/// During CIE/FDE parsing, if a relative pointer is encountered for a base
875/// address that is unknown, an Err will be returned.
876///
877/// ```
878/// use gimli::BaseAddresses;
879///
880/// # fn foo() {
881/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!();
882/// # let address_of_eh_frame_section_in_memory = unimplemented!();
883/// # let address_of_text_section_in_memory = unimplemented!();
884/// # let address_of_got_section_in_memory = unimplemented!();
885/// # let address_of_the_start_of_current_func = unimplemented!();
886/// let bases = BaseAddresses::default()
887///     .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory)
888///     .set_eh_frame(address_of_eh_frame_section_in_memory)
889///     .set_text(address_of_text_section_in_memory)
890///     .set_got(address_of_got_section_in_memory);
891/// # let _ = bases;
892/// # }
893/// ```
894#[derive(Clone, Default, Debug, PartialEq, Eq)]
895pub struct BaseAddresses {
896    /// The base addresses to use for pointers in the `.eh_frame_hdr` section.
897    pub eh_frame_hdr: SectionBaseAddresses,
898
899    /// The base addresses to use for pointers in the `.eh_frame` section.
900    pub eh_frame: SectionBaseAddresses,
901}
902
903/// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers
904/// in a particular section.
905///
906/// See `BaseAddresses` for methods that are helpful in setting these addresses.
907#[derive(Clone, Default, Debug, PartialEq, Eq)]
908pub struct SectionBaseAddresses {
909    /// The address of the section containing the pointer.
910    pub section: Option<u64>,
911
912    /// The base address for text relative pointers.
913    /// This is generally the address of the `.text` section.
914    pub text: Option<u64>,
915
916    /// The base address for data relative pointers.
917    ///
918    /// For pointers in the `.eh_frame_hdr` section, this is the address
919    /// of the `.eh_frame_hdr` section
920    ///
921    /// For pointers in the `.eh_frame` section, this is generally the
922    /// global pointer, such as the address of the `.got` section.
923    pub data: Option<u64>,
924}
925
926impl BaseAddresses {
927    /// Set the `.eh_frame_hdr` section base address.
928    #[inline]
929    pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self {
930        self.eh_frame_hdr.section = Some(addr);
931        self.eh_frame_hdr.data = Some(addr);
932        self
933    }
934
935    /// Set the `.eh_frame` section base address.
936    #[inline]
937    pub fn set_eh_frame(mut self, addr: u64) -> Self {
938        self.eh_frame.section = Some(addr);
939        self
940    }
941
942    /// Set the `.text` section base address.
943    #[inline]
944    pub fn set_text(mut self, addr: u64) -> Self {
945        self.eh_frame_hdr.text = Some(addr);
946        self.eh_frame.text = Some(addr);
947        self
948    }
949
950    /// Set the `.got` section base address.
951    #[inline]
952    pub fn set_got(mut self, addr: u64) -> Self {
953        self.eh_frame.data = Some(addr);
954        self
955    }
956}
957
958/// An iterator over CIE and FDE entries in a `.debug_frame` or `.eh_frame`
959/// section.
960///
961/// Some pointers may be encoded relative to various base addresses. Use the
962/// [`BaseAddresses`](./struct.BaseAddresses.html) parameter to provide them. By
963/// default, none are provided. If a relative pointer is encountered for a base
964/// address that is unknown, an `Err` will be returned and iteration will abort.
965///
966/// Can be [used with
967/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
968///
969/// ```
970/// use gimli::{BaseAddresses, EhFrame, EndianSlice, NativeEndian, UnwindSection};
971///
972/// # fn foo() -> gimli::Result<()> {
973/// # let read_eh_frame_somehow = || unimplemented!();
974/// let eh_frame = EhFrame::new(read_eh_frame_somehow(), NativeEndian);
975///
976/// # let address_of_eh_frame_hdr_section_in_memory = unimplemented!();
977/// # let address_of_eh_frame_section_in_memory = unimplemented!();
978/// # let address_of_text_section_in_memory = unimplemented!();
979/// # let address_of_got_section_in_memory = unimplemented!();
980/// # let address_of_the_start_of_current_func = unimplemented!();
981/// // Provide base addresses for relative pointers.
982/// let bases = BaseAddresses::default()
983///     .set_eh_frame_hdr(address_of_eh_frame_hdr_section_in_memory)
984///     .set_eh_frame(address_of_eh_frame_section_in_memory)
985///     .set_text(address_of_text_section_in_memory)
986///     .set_got(address_of_got_section_in_memory);
987///
988/// let mut entries = eh_frame.entries(&bases);
989///
990/// # let do_stuff_with = |_| unimplemented!();
991/// while let Some(entry) = entries.next()? {
992///     do_stuff_with(entry)
993/// }
994/// # unreachable!()
995/// # }
996/// ```
997#[derive(Clone, Debug)]
998pub struct CfiEntriesIter<'bases, Section, R>
999where
1000    R: Reader,
1001    Section: UnwindSection<R>,
1002{
1003    section: Section,
1004    bases: &'bases BaseAddresses,
1005    input: R,
1006}
1007
1008impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R>
1009where
1010    R: Reader,
1011    Section: UnwindSection<R>,
1012{
1013    /// Advance the iterator to the next entry.
1014    pub fn next(&mut self) -> Result<Option<CieOrFde<'bases, Section, R>>> {
1015        loop {
1016            if self.input.is_empty() {
1017                return Ok(None);
1018            }
1019
1020            match parse_cfi_entry(self.bases, &self.section, &mut self.input) {
1021                Ok(Some(entry)) => return Ok(Some(entry)),
1022                Err(e) => {
1023                    self.input.empty();
1024                    return Err(e);
1025                }
1026                Ok(None) => {
1027                    if Section::has_zero_terminator() {
1028                        self.input.empty();
1029                        return Ok(None);
1030                    }
1031
1032                    // Hack: If we get to here, then we're reading `.debug_frame` and
1033                    // encountered a length of 0. This is a compiler or linker bug
1034                    // (originally seen for NASM, fixed in 2.15rc9).
1035                    // Skip this value and try again.
1036                    continue;
1037                }
1038            }
1039        }
1040    }
1041}
1042
1043#[cfg(feature = "fallible-iterator")]
1044impl<'bases, Section, R> fallible_iterator::FallibleIterator for CfiEntriesIter<'bases, Section, R>
1045where
1046    R: Reader,
1047    Section: UnwindSection<R>,
1048{
1049    type Item = CieOrFde<'bases, Section, R>;
1050    type Error = Error;
1051
1052    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
1053        CfiEntriesIter::next(self)
1054    }
1055}
1056
1057/// Either a `CommonInformationEntry` (CIE) or a `FrameDescriptionEntry` (FDE).
1058#[derive(Clone, Debug, PartialEq, Eq)]
1059pub enum CieOrFde<'bases, Section, R>
1060where
1061    R: Reader,
1062    Section: UnwindSection<R>,
1063{
1064    /// This CFI entry is a `CommonInformationEntry`.
1065    Cie(CommonInformationEntry<R>),
1066    /// This CFI entry is a `FrameDescriptionEntry`, however fully parsing it
1067    /// requires parsing its CIE first, so it is left in a partially parsed
1068    /// state.
1069    Fde(PartialFrameDescriptionEntry<'bases, Section, R>),
1070}
1071
1072fn parse_cfi_entry<'bases, Section, R>(
1073    bases: &'bases BaseAddresses,
1074    section: &Section,
1075    input: &mut R,
1076) -> Result<Option<CieOrFde<'bases, Section, R>>>
1077where
1078    R: Reader,
1079    Section: UnwindSection<R>,
1080{
1081    let offset = input.offset_from(section.section());
1082    let (length, format) = input.read_initial_length()?;
1083    if length.into_u64() == 0 {
1084        return Ok(None);
1085    }
1086
1087    let mut rest = input.split(length)?;
1088    let cie_offset_base = rest.offset_from(section.section());
1089    let cie_id_or_offset = match Section::cie_offset_encoding(format) {
1090        CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?,
1091        CieOffsetEncoding::U64 => rest.read_u64()?,
1092    };
1093
1094    if Section::is_cie(format, cie_id_or_offset) {
1095        let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?;
1096        Ok(Some(CieOrFde::Cie(cie)))
1097    } else {
1098        let cie_offset = R::Offset::from_u64(cie_id_or_offset)?;
1099        let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) {
1100            None => return Err(Error::OffsetOutOfBounds),
1101            Some(cie_offset) => cie_offset,
1102        };
1103
1104        let fde = PartialFrameDescriptionEntry {
1105            offset,
1106            length,
1107            format,
1108            cie_offset: cie_offset.into(),
1109            rest,
1110            section: section.clone(),
1111            bases,
1112        };
1113
1114        Ok(Some(CieOrFde::Fde(fde)))
1115    }
1116}
1117
1118/// We support the z-style augmentation [defined by `.eh_frame`][ehframe].
1119///
1120/// [ehframe]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
1121#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1122pub struct Augmentation {
1123    /// > A 'L' may be present at any position after the first character of the
1124    /// > string. This character may only be present if 'z' is the first character
1125    /// > of the string. If present, it indicates the presence of one argument in
1126    /// > the Augmentation Data of the CIE, and a corresponding argument in the
1127    /// > Augmentation Data of the FDE. The argument in the Augmentation Data of
1128    /// > the CIE is 1-byte and represents the pointer encoding used for the
1129    /// > argument in the Augmentation Data of the FDE, which is the address of a
1130    /// > language-specific data area (LSDA). The size of the LSDA pointer is
1131    /// > specified by the pointer encoding used.
1132    lsda: Option<constants::DwEhPe>,
1133
1134    /// > A 'P' may be present at any position after the first character of the
1135    /// > string. This character may only be present if 'z' is the first character
1136    /// > of the string. If present, it indicates the presence of two arguments in
1137    /// > the Augmentation Data of the CIE. The first argument is 1-byte and
1138    /// > represents the pointer encoding used for the second argument, which is
1139    /// > the address of a personality routine handler. The size of the
1140    /// > personality routine pointer is specified by the pointer encoding used.
1141    personality: Option<(constants::DwEhPe, Pointer)>,
1142
1143    /// > A 'R' may be present at any position after the first character of the
1144    /// > string. This character may only be present if 'z' is the first character
1145    /// > of the string. If present, The Augmentation Data shall include a 1 byte
1146    /// > argument that represents the pointer encoding for the address pointers
1147    /// > used in the FDE.
1148    fde_address_encoding: Option<constants::DwEhPe>,
1149
1150    /// True if this CIE's FDEs are trampolines for signal handlers.
1151    is_signal_trampoline: bool,
1152}
1153
1154impl Augmentation {
1155    fn parse<Section, R>(
1156        augmentation_str: &mut R,
1157        bases: &BaseAddresses,
1158        address_size: u8,
1159        section: &Section,
1160        input: &mut R,
1161    ) -> Result<Augmentation>
1162    where
1163        R: Reader,
1164        Section: UnwindSection<R>,
1165    {
1166        debug_assert!(
1167            !augmentation_str.is_empty(),
1168            "Augmentation::parse should only be called if we have an augmentation"
1169        );
1170
1171        let mut augmentation = Augmentation::default();
1172
1173        let mut parsed_first = false;
1174        let mut data = None;
1175
1176        while !augmentation_str.is_empty() {
1177            let ch = augmentation_str.read_u8()?;
1178            match ch {
1179                b'z' => {
1180                    if parsed_first {
1181                        return Err(Error::UnknownAugmentation);
1182                    }
1183
1184                    let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?;
1185                    data = Some(input.split(augmentation_length)?);
1186                }
1187                b'L' => {
1188                    let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1189                    let encoding = parse_pointer_encoding(rest)?;
1190                    augmentation.lsda = Some(encoding);
1191                }
1192                b'P' => {
1193                    let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1194                    let encoding = parse_pointer_encoding(rest)?;
1195                    let parameters = PointerEncodingParameters {
1196                        bases: &bases.eh_frame,
1197                        func_base: None,
1198                        address_size,
1199                        section: section.section(),
1200                    };
1201
1202                    let personality = parse_encoded_pointer(encoding, &parameters, rest)?;
1203                    augmentation.personality = Some((encoding, personality));
1204                }
1205                b'R' => {
1206                    let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1207                    let encoding = parse_pointer_encoding(rest)?;
1208                    augmentation.fde_address_encoding = Some(encoding);
1209                }
1210                b'S' => augmentation.is_signal_trampoline = true,
1211                _ => return Err(Error::UnknownAugmentation),
1212            }
1213
1214            parsed_first = true;
1215        }
1216
1217        Ok(augmentation)
1218    }
1219}
1220
1221/// Parsed augmentation data for a `FrameDescriptEntry`.
1222#[derive(Clone, Debug, Default, PartialEq, Eq)]
1223struct AugmentationData {
1224    lsda: Option<Pointer>,
1225}
1226
1227impl AugmentationData {
1228    fn parse<R: Reader>(
1229        augmentation: &Augmentation,
1230        encoding_parameters: &PointerEncodingParameters<'_, R>,
1231        input: &mut R,
1232    ) -> Result<AugmentationData> {
1233        // In theory, we should be iterating over the original augmentation
1234        // string, interpreting each character, and reading the appropriate bits
1235        // out of the augmentation data as we go. However, the only character
1236        // that defines augmentation data in the FDE is the 'L' character, so we
1237        // can just check for its presence directly.
1238
1239        let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?;
1240        let rest = &mut input.split(aug_data_len)?;
1241        let mut augmentation_data = AugmentationData::default();
1242        if let Some(encoding) = augmentation.lsda {
1243            let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?;
1244            augmentation_data.lsda = Some(lsda);
1245        }
1246        Ok(augmentation_data)
1247    }
1248}
1249
1250/// > A Common Information Entry holds information that is shared among many
1251/// > Frame Description Entries. There is at least one CIE in every non-empty
1252/// > `.debug_frame` section.
1253#[derive(Clone, Debug, PartialEq, Eq)]
1254pub struct CommonInformationEntry<R, Offset = <R as Reader>::Offset>
1255where
1256    R: Reader<Offset = Offset>,
1257    Offset: ReaderOffset,
1258{
1259    /// The offset of this entry from the start of its containing section.
1260    offset: Offset,
1261
1262    /// > A constant that gives the number of bytes of the CIE structure, not
1263    /// > including the length field itself (see Section 7.2.2). The size of the
1264    /// > length field plus the value of length must be an integral multiple of
1265    /// > the address size.
1266    length: Offset,
1267
1268    format: Format,
1269
1270    /// > A version number (see Section 7.23). This number is specific to the
1271    /// > call frame information and is independent of the DWARF version number.
1272    version: u8,
1273
1274    /// The parsed augmentation, if any.
1275    augmentation: Option<Augmentation>,
1276
1277    /// > The size of a target address in this CIE and any FDEs that use it, in
1278    /// > bytes. If a compilation unit exists for this frame, its address size
1279    /// > must match the address size here.
1280    address_size: u8,
1281
1282    /// "A constant that is factored out of all advance location instructions
1283    /// (see Section 6.4.2.1)."
1284    code_alignment_factor: u64,
1285
1286    /// > A constant that is factored out of certain offset instructions (see
1287    /// > below). The resulting value is (operand * data_alignment_factor).
1288    data_alignment_factor: i64,
1289
1290    /// > An unsigned LEB128 constant that indicates which column in the rule
1291    /// > table represents the return address of the function. Note that this
1292    /// > column might not correspond to an actual machine register.
1293    return_address_register: Register,
1294
1295    /// > A sequence of rules that are interpreted to create the initial setting
1296    /// > of each column in the table.
1297    ///
1298    /// > The default rule for all columns before interpretation of the initial
1299    /// > instructions is the undefined rule. However, an ABI authoring body or a
1300    /// > compilation system authoring body may specify an alternate default
1301    /// > value for any or all columns.
1302    ///
1303    /// This is followed by `DW_CFA_nop` padding until the end of `length` bytes
1304    /// in the input.
1305    initial_instructions: R,
1306}
1307
1308impl<R: Reader> CommonInformationEntry<R> {
1309    fn parse<Section: UnwindSection<R>>(
1310        bases: &BaseAddresses,
1311        section: &Section,
1312        input: &mut R,
1313    ) -> Result<CommonInformationEntry<R>> {
1314        match parse_cfi_entry(bases, section, input)? {
1315            Some(CieOrFde::Cie(cie)) => Ok(cie),
1316            Some(CieOrFde::Fde(_)) => Err(Error::NotCieId),
1317            None => Err(Error::NoEntryAtGivenOffset),
1318        }
1319    }
1320
1321    fn parse_rest<Section: UnwindSection<R>>(
1322        offset: R::Offset,
1323        length: R::Offset,
1324        format: Format,
1325        bases: &BaseAddresses,
1326        section: &Section,
1327        mut rest: R,
1328    ) -> Result<CommonInformationEntry<R>> {
1329        let version = rest.read_u8()?;
1330
1331        // Version 1 of `.debug_frame` corresponds to DWARF 2, and then for
1332        // DWARF 3 and 4, I think they decided to just match the standard's
1333        // version.
1334        match version {
1335            1 | 3 | 4 => (),
1336            _ => return Err(Error::UnknownVersion(u64::from(version))),
1337        }
1338
1339        let mut augmentation_string = rest.read_null_terminated_slice()?;
1340
1341        let address_size = if Section::has_address_and_segment_sizes(version) {
1342            let address_size = rest.read_address_size()?;
1343            let segment_size = rest.read_u8()?;
1344            if segment_size != 0 {
1345                return Err(Error::UnsupportedSegmentSize);
1346            }
1347            address_size
1348        } else {
1349            section.address_size()
1350        };
1351
1352        let code_alignment_factor = rest.read_uleb128()?;
1353        let data_alignment_factor = rest.read_sleb128()?;
1354
1355        let return_address_register = if version == 1 {
1356            Register(rest.read_u8()?.into())
1357        } else {
1358            rest.read_uleb128().and_then(Register::from_u64)?
1359        };
1360
1361        let augmentation = if augmentation_string.is_empty() {
1362            None
1363        } else {
1364            Some(Augmentation::parse(
1365                &mut augmentation_string,
1366                bases,
1367                address_size,
1368                section,
1369                &mut rest,
1370            )?)
1371        };
1372
1373        let entry = CommonInformationEntry {
1374            offset,
1375            length,
1376            format,
1377            version,
1378            augmentation,
1379            address_size,
1380            code_alignment_factor,
1381            data_alignment_factor,
1382            return_address_register,
1383            initial_instructions: rest,
1384        };
1385
1386        Ok(entry)
1387    }
1388}
1389
1390/// # Signal Safe Methods
1391///
1392/// These methods are guaranteed not to allocate, acquire locks, or perform any
1393/// other signal-unsafe operations.
1394impl<R: Reader> CommonInformationEntry<R> {
1395    /// Get the offset of this entry from the start of its containing section.
1396    pub fn offset(&self) -> R::Offset {
1397        self.offset
1398    }
1399
1400    /// Return the encoding parameters for this CIE.
1401    pub fn encoding(&self) -> Encoding {
1402        Encoding {
1403            format: self.format,
1404            version: u16::from(self.version),
1405            address_size: self.address_size,
1406        }
1407    }
1408
1409    /// The size of addresses (in bytes) in this CIE.
1410    pub fn address_size(&self) -> u8 {
1411        self.address_size
1412    }
1413
1414    /// Iterate over this CIE's initial instructions.
1415    ///
1416    /// Can be [used with
1417    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
1418    pub fn instructions<'a, Section>(
1419        &self,
1420        section: &'a Section,
1421        bases: &'a BaseAddresses,
1422    ) -> CallFrameInstructionIter<'a, R>
1423    where
1424        Section: UnwindSection<R>,
1425    {
1426        CallFrameInstructionIter {
1427            input: self.initial_instructions.clone(),
1428            address_encoding: None,
1429            parameters: PointerEncodingParameters {
1430                bases: &bases.eh_frame,
1431                func_base: None,
1432                address_size: self.address_size,
1433                section: section.section(),
1434            },
1435            vendor: section.vendor(),
1436        }
1437    }
1438
1439    /// > A constant that gives the number of bytes of the CIE structure, not
1440    /// > including the length field itself (see Section 7.2.2). The size of the
1441    /// > length field plus the value of length must be an integral multiple of
1442    /// > the address size.
1443    pub fn entry_len(&self) -> R::Offset {
1444        self.length
1445    }
1446
1447    /// > A version number (see Section 7.23). This number is specific to the
1448    /// > call frame information and is independent of the DWARF version number.
1449    pub fn version(&self) -> u8 {
1450        self.version
1451    }
1452
1453    /// Get the augmentation data, if any exists.
1454    ///
1455    /// The only augmentation understood by `gimli` is that which is defined by
1456    /// `.eh_frame`.
1457    pub fn augmentation(&self) -> Option<&Augmentation> {
1458        self.augmentation.as_ref()
1459    }
1460
1461    /// True if this CIE's FDEs have a LSDA.
1462    pub fn has_lsda(&self) -> bool {
1463        self.augmentation.map_or(false, |a| a.lsda.is_some())
1464    }
1465
1466    /// Return the encoding of the LSDA address for this CIE's FDEs.
1467    pub fn lsda_encoding(&self) -> Option<constants::DwEhPe> {
1468        self.augmentation.and_then(|a| a.lsda)
1469    }
1470
1471    /// Return the encoding and address of the personality routine handler
1472    /// for this CIE's FDEs.
1473    pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> {
1474        self.augmentation.as_ref().and_then(|a| a.personality)
1475    }
1476
1477    /// Return the address of the personality routine handler
1478    /// for this CIE's FDEs.
1479    pub fn personality(&self) -> Option<Pointer> {
1480        self.augmentation
1481            .as_ref()
1482            .and_then(|a| a.personality)
1483            .map(|(_, p)| p)
1484    }
1485
1486    /// Return the encoding of the addresses for this CIE's FDEs.
1487    pub fn fde_address_encoding(&self) -> Option<constants::DwEhPe> {
1488        self.augmentation.and_then(|a| a.fde_address_encoding)
1489    }
1490
1491    /// True if this CIE's FDEs are trampolines for signal handlers.
1492    pub fn is_signal_trampoline(&self) -> bool {
1493        self.augmentation.map_or(false, |a| a.is_signal_trampoline)
1494    }
1495
1496    /// > A constant that is factored out of all advance location instructions
1497    /// > (see Section 6.4.2.1).
1498    pub fn code_alignment_factor(&self) -> u64 {
1499        self.code_alignment_factor
1500    }
1501
1502    /// > A constant that is factored out of certain offset instructions (see
1503    /// > below). The resulting value is (operand * data_alignment_factor).
1504    pub fn data_alignment_factor(&self) -> i64 {
1505        self.data_alignment_factor
1506    }
1507
1508    /// > An unsigned ... constant that indicates which column in the rule
1509    /// > table represents the return address of the function. Note that this
1510    /// > column might not correspond to an actual machine register.
1511    pub fn return_address_register(&self) -> Register {
1512        self.return_address_register
1513    }
1514}
1515
1516/// A partially parsed `FrameDescriptionEntry`.
1517///
1518/// Fully parsing this FDE requires first parsing its CIE.
1519#[derive(Clone, Debug, PartialEq, Eq)]
1520pub struct PartialFrameDescriptionEntry<'bases, Section, R>
1521where
1522    R: Reader,
1523    Section: UnwindSection<R>,
1524{
1525    offset: R::Offset,
1526    length: R::Offset,
1527    format: Format,
1528    cie_offset: Section::Offset,
1529    rest: R,
1530    section: Section,
1531    bases: &'bases BaseAddresses,
1532}
1533
1534impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R>
1535where
1536    R: Reader,
1537    Section: UnwindSection<R>,
1538{
1539    fn parse_partial(
1540        section: &Section,
1541        bases: &'bases BaseAddresses,
1542        input: &mut R,
1543    ) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> {
1544        match parse_cfi_entry(bases, section, input)? {
1545            Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer),
1546            Some(CieOrFde::Fde(partial)) => Ok(partial),
1547            None => Err(Error::NoEntryAtGivenOffset),
1548        }
1549    }
1550
1551    /// Fully parse this FDE.
1552    ///
1553    /// You must provide a function get its associated CIE (either by parsing it
1554    /// on demand, or looking it up in some table mapping offsets to CIEs that
1555    /// you've already parsed, etc.)
1556    pub fn parse<F>(&self, get_cie: F) -> Result<FrameDescriptionEntry<R>>
1557    where
1558        F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
1559    {
1560        FrameDescriptionEntry::parse_rest(
1561            self.offset,
1562            self.length,
1563            self.format,
1564            self.cie_offset,
1565            self.rest.clone(),
1566            &self.section,
1567            self.bases,
1568            get_cie,
1569        )
1570    }
1571
1572    /// Get the offset of this entry from the start of its containing section.
1573    pub fn offset(&self) -> R::Offset {
1574        self.offset
1575    }
1576
1577    /// Get the offset of this FDE's CIE.
1578    pub fn cie_offset(&self) -> Section::Offset {
1579        self.cie_offset
1580    }
1581
1582    /// > A constant that gives the number of bytes of the header and
1583    /// > instruction stream for this function, not including the length field
1584    /// > itself (see Section 7.2.2). The size of the length field plus the value
1585    /// > of length must be an integral multiple of the address size.
1586    pub fn entry_len(&self) -> R::Offset {
1587        self.length
1588    }
1589}
1590
1591/// A `FrameDescriptionEntry` is a set of CFA instructions for an address range.
1592#[derive(Clone, Debug, PartialEq, Eq)]
1593pub struct FrameDescriptionEntry<R, Offset = <R as Reader>::Offset>
1594where
1595    R: Reader<Offset = Offset>,
1596    Offset: ReaderOffset,
1597{
1598    /// The start of this entry within its containing section.
1599    offset: Offset,
1600
1601    /// > A constant that gives the number of bytes of the header and
1602    /// > instruction stream for this function, not including the length field
1603    /// > itself (see Section 7.2.2). The size of the length field plus the value
1604    /// > of length must be an integral multiple of the address size.
1605    length: Offset,
1606
1607    format: Format,
1608
1609    /// "A constant offset into the .debug_frame section that denotes the CIE
1610    /// that is associated with this FDE."
1611    ///
1612    /// This is the CIE at that offset.
1613    cie: CommonInformationEntry<R, Offset>,
1614
1615    /// > The address of the first location associated with this table entry. If
1616    /// > the segment_size field of this FDE's CIE is non-zero, the initial
1617    /// > location is preceded by a segment selector of the given length.
1618    initial_address: u64,
1619
1620    /// "The number of bytes of program instructions described by this entry."
1621    address_range: u64,
1622
1623    /// The parsed augmentation data, if we have any.
1624    augmentation: Option<AugmentationData>,
1625
1626    /// "A sequence of table defining instructions that are described below."
1627    ///
1628    /// This is followed by `DW_CFA_nop` padding until `length` bytes of the
1629    /// input are consumed.
1630    instructions: R,
1631}
1632
1633impl<R: Reader> FrameDescriptionEntry<R> {
1634    fn parse_rest<Section, F>(
1635        offset: R::Offset,
1636        length: R::Offset,
1637        format: Format,
1638        cie_pointer: Section::Offset,
1639        mut rest: R,
1640        section: &Section,
1641        bases: &BaseAddresses,
1642        mut get_cie: F,
1643    ) -> Result<FrameDescriptionEntry<R>>
1644    where
1645        Section: UnwindSection<R>,
1646        F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
1647    {
1648        let cie = get_cie(section, bases, cie_pointer)?;
1649
1650        let mut parameters = PointerEncodingParameters {
1651            bases: &bases.eh_frame,
1652            func_base: None,
1653            address_size: cie.address_size,
1654            section: section.section(),
1655        };
1656
1657        let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, &parameters)?;
1658        parameters.func_base = Some(initial_address);
1659
1660        let aug_data = if let Some(ref augmentation) = cie.augmentation {
1661            Some(AugmentationData::parse(
1662                augmentation,
1663                &parameters,
1664                &mut rest,
1665            )?)
1666        } else {
1667            None
1668        };
1669
1670        let entry = FrameDescriptionEntry {
1671            offset,
1672            length,
1673            format,
1674            cie,
1675            initial_address,
1676            address_range,
1677            augmentation: aug_data,
1678            instructions: rest,
1679        };
1680
1681        Ok(entry)
1682    }
1683
1684    fn parse_addresses(
1685        input: &mut R,
1686        cie: &CommonInformationEntry<R>,
1687        parameters: &PointerEncodingParameters<'_, R>,
1688    ) -> Result<(u64, u64)> {
1689        let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding);
1690        if let Some(encoding) = encoding {
1691            // Ignore indirection.
1692            let initial_address = parse_encoded_pointer(encoding, parameters, input)?.pointer();
1693            let address_range = parse_encoded_value(encoding, parameters, input)?;
1694            Ok((initial_address, address_range))
1695        } else {
1696            let initial_address = input.read_address(cie.address_size)?;
1697            let address_range = input.read_address(cie.address_size)?;
1698            Ok((initial_address, address_range))
1699        }
1700    }
1701
1702    /// Return the table of unwind information for this FDE.
1703    #[inline]
1704    pub fn rows<'a, 'ctx, Section, S>(
1705        &self,
1706        section: &'a Section,
1707        bases: &'a BaseAddresses,
1708        ctx: &'ctx mut UnwindContext<R::Offset, S>,
1709    ) -> Result<UnwindTable<'a, 'ctx, R, S>>
1710    where
1711        Section: UnwindSection<R>,
1712        S: UnwindContextStorage<R::Offset>,
1713    {
1714        UnwindTable::new(section, bases, ctx, self)
1715    }
1716
1717    /// Find the frame unwind information for the given address.
1718    ///
1719    /// If found, the unwind information is returned along with the reset
1720    /// context in the form `Ok((unwind_info, context))`. If not found,
1721    /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or
1722    /// CFI evaluation fails, the error is returned.
1723    pub fn unwind_info_for_address<'ctx, Section, S>(
1724        &self,
1725        section: &Section,
1726        bases: &BaseAddresses,
1727        ctx: &'ctx mut UnwindContext<R::Offset, S>,
1728        address: u64,
1729    ) -> Result<&'ctx UnwindTableRow<R::Offset, S>>
1730    where
1731        Section: UnwindSection<R>,
1732        S: UnwindContextStorage<R::Offset>,
1733    {
1734        let mut table = self.rows(section, bases, ctx)?;
1735        while let Some(row) = table.next_row()? {
1736            if row.contains(address) {
1737                return Ok(table.ctx.row());
1738            }
1739        }
1740        Err(Error::NoUnwindInfoForAddress)
1741    }
1742}
1743
1744/// # Signal Safe Methods
1745///
1746/// These methods are guaranteed not to allocate, acquire locks, or perform any
1747/// other signal-unsafe operations.
1748#[allow(clippy::len_without_is_empty)]
1749impl<R: Reader> FrameDescriptionEntry<R> {
1750    /// Get the offset of this entry from the start of its containing section.
1751    pub fn offset(&self) -> R::Offset {
1752        self.offset
1753    }
1754
1755    /// Get a reference to this FDE's CIE.
1756    pub fn cie(&self) -> &CommonInformationEntry<R> {
1757        &self.cie
1758    }
1759
1760    /// > A constant that gives the number of bytes of the header and
1761    /// > instruction stream for this function, not including the length field
1762    /// > itself (see Section 7.2.2). The size of the length field plus the value
1763    /// > of length must be an integral multiple of the address size.
1764    pub fn entry_len(&self) -> R::Offset {
1765        self.length
1766    }
1767
1768    /// Iterate over this FDE's instructions.
1769    ///
1770    /// Will not include the CIE's initial instructions, if you want those do
1771    /// `fde.cie().instructions()` first.
1772    ///
1773    /// Can be [used with
1774    /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
1775    pub fn instructions<'a, Section>(
1776        &self,
1777        section: &'a Section,
1778        bases: &'a BaseAddresses,
1779    ) -> CallFrameInstructionIter<'a, R>
1780    where
1781        Section: UnwindSection<R>,
1782    {
1783        CallFrameInstructionIter {
1784            input: self.instructions.clone(),
1785            address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding),
1786            parameters: PointerEncodingParameters {
1787                bases: &bases.eh_frame,
1788                func_base: None,
1789                address_size: self.cie.address_size,
1790                section: section.section(),
1791            },
1792            vendor: section.vendor(),
1793        }
1794    }
1795
1796    /// The first address for which this entry has unwind information for.
1797    pub fn initial_address(&self) -> u64 {
1798        self.initial_address
1799    }
1800
1801    /// One more than the last address that this entry has unwind information for.
1802    ///
1803    /// This uses wrapping arithmetic, so the result may be less than
1804    /// `initial_address`.
1805    pub fn end_address(&self) -> u64 {
1806        self.initial_address
1807            .wrapping_add_sized(self.address_range, self.cie.address_size)
1808    }
1809
1810    /// The number of bytes of instructions that this entry has unwind
1811    /// information for.
1812    pub fn len(&self) -> u64 {
1813        self.address_range
1814    }
1815
1816    /// Return `true` if the given address is within this FDE, `false`
1817    /// otherwise.
1818    ///
1819    /// This is equivalent to `entry.initial_address() <= address <
1820    /// entry.initial_address() + entry.len()`.
1821    pub fn contains(&self, address: u64) -> bool {
1822        self.initial_address() <= address && address < self.end_address()
1823    }
1824
1825    /// The address of this FDE's language-specific data area (LSDA), if it has
1826    /// any.
1827    pub fn lsda(&self) -> Option<Pointer> {
1828        self.augmentation.as_ref().and_then(|a| a.lsda)
1829    }
1830
1831    /// Return true if this FDE's function is a trampoline for a signal handler.
1832    #[inline]
1833    pub fn is_signal_trampoline(&self) -> bool {
1834        self.cie().is_signal_trampoline()
1835    }
1836
1837    /// Return the address of the FDE's function's personality routine
1838    /// handler. The personality routine does language-specific clean up when
1839    /// unwinding the stack frames with the intent to not run them again.
1840    #[inline]
1841    pub fn personality(&self) -> Option<Pointer> {
1842        self.cie().personality()
1843    }
1844}
1845
1846/// Specification of what storage should be used for [`UnwindContext`].
1847///
1848#[cfg_attr(
1849    feature = "read",
1850    doc = "
1851Normally you would only need to use [`StoreOnHeap`], which places the stack
1852on the heap using [`Box`]. This is the default storage type parameter for [`UnwindContext`].
1853
1854You may want to supply your own storage type for one of the following reasons:
1855
1856  1. In rare cases you may run into failed unwinds due to the fixed stack size
1857     used by [`StoreOnHeap`], so you may want to try a larger `Box`. If denial
1858     of service is not a concern, then you could also try a `Vec`-based stack which
1859     can grow as needed.
1860  2. You may want to avoid heap allocations entirely. You can use a fixed-size
1861     stack with in-line arrays, which will place the entire storage in-line into
1862     [`UnwindContext`].
1863"
1864)]
1865///
1866/// Here's an implementation which uses a fixed-size stack and allocates everything in-line,
1867/// which will cause `UnwindContext` to be large:
1868///
1869/// ```rust,no_run
1870/// # use gimli::*;
1871/// #
1872/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>)
1873/// #            -> gimli::Result<()> {
1874/// # let eh_frame: gimli::EhFrame<_> = unreachable!();
1875/// # let bases = unimplemented!();
1876/// #
1877/// struct StoreOnStack;
1878///
1879/// impl<T: ReaderOffset> UnwindContextStorage<T> for StoreOnStack {
1880///     type Rules = [(Register, RegisterRule<T>); 192];
1881///     type Stack = [UnwindTableRow<T, Self>; 4];
1882/// }
1883///
1884/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in();
1885///
1886/// // Initialize the context by evaluating the CIE's initial instruction program,
1887/// // and generate the unwind table.
1888/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?;
1889/// while let Some(row) = table.next_row()? {
1890///     // Do stuff with each row...
1891/// #   let _ = row;
1892/// }
1893/// # unreachable!()
1894/// # }
1895/// ```
1896pub trait UnwindContextStorage<T: ReaderOffset>: Sized {
1897    /// The storage used for register rules in a unwind table row.
1898    ///
1899    /// Note that this is nested within the stack.
1900    type Rules: ArrayLike<Item = (Register, RegisterRule<T>)>;
1901
1902    /// The storage used for unwind table row stack.
1903    type Stack: ArrayLike<Item = UnwindTableRow<T, Self>>;
1904}
1905
1906#[cfg(feature = "read")]
1907const MAX_RULES: usize = 192;
1908#[cfg(feature = "read")]
1909const MAX_UNWIND_STACK_DEPTH: usize = 4;
1910
1911#[cfg(feature = "read")]
1912impl<T: ReaderOffset> UnwindContextStorage<T> for StoreOnHeap {
1913    type Rules = [(Register, RegisterRule<T>); MAX_RULES];
1914    type Stack = Box<[UnwindTableRow<T, Self>; MAX_UNWIND_STACK_DEPTH]>;
1915}
1916
1917/// Common context needed when evaluating the call frame unwinding information.
1918///
1919/// By default, this structure is small and allocates its internal storage
1920/// on the heap using [`Box`] during [`UnwindContext::new`].
1921///
1922/// This can be overridden by providing a custom [`UnwindContextStorage`] type parameter.
1923/// When using a custom storage with in-line arrays, the [`UnwindContext`] type itself
1924/// will be big, so in that case it's recommended to place [`UnwindContext`] on the
1925/// heap, e.g. using `Box::new(UnwindContext::<R, MyCustomStorage>::new_in())`.
1926///
1927/// To avoid re-allocating the context multiple times when evaluating multiple
1928/// CFI programs, the same [`UnwindContext`] can be reused for multiple unwinds.
1929///
1930/// ```
1931/// use gimli::{UnwindContext, UnwindTable};
1932///
1933/// # fn foo<'a>(some_fde: gimli::FrameDescriptionEntry<gimli::EndianSlice<'a, gimli::LittleEndian>>)
1934/// #            -> gimli::Result<()> {
1935/// # let eh_frame: gimli::EhFrame<_> = unreachable!();
1936/// # let bases = unimplemented!();
1937/// // An uninitialized context.
1938/// let mut ctx = UnwindContext::new();
1939///
1940/// // Initialize the context by evaluating the CIE's initial instruction program,
1941/// // and generate the unwind table.
1942/// let mut table = some_fde.rows(&eh_frame, &bases, &mut ctx)?;
1943/// while let Some(row) = table.next_row()? {
1944///     // Do stuff with each row...
1945/// #   let _ = row;
1946/// }
1947/// # unreachable!()
1948/// # }
1949/// ```
1950#[derive(Clone, PartialEq, Eq)]
1951pub struct UnwindContext<T, S = StoreOnHeap>
1952where
1953    T: ReaderOffset,
1954    S: UnwindContextStorage<T>,
1955{
1956    // Stack of rows. The last row is the row currently being built by the
1957    // program. There is always at least one row. The vast majority of CFI
1958    // programs will only ever have one row on the stack.
1959    stack: ArrayVec<S::Stack>,
1960
1961    // If we are evaluating an FDE's instructions, then `is_initialized` will be
1962    // `true`. If `initial_rule` is `Some`, then the initial register rules are either
1963    // all default rules or have just 1 non-default rule, stored in `initial_rule`.
1964    // If it's `None`, `stack[0]` will contain the initial register rules
1965    // described by the CIE's initial instructions. These rules are used by
1966    // `DW_CFA_restore`. Otherwise, when we are currently evaluating a CIE's
1967    // initial instructions, `is_initialized` will be `false` and initial rules
1968    // cannot be read.
1969    initial_rule: Option<(Register, RegisterRule<T>)>,
1970
1971    is_initialized: bool,
1972}
1973
1974impl<T, S> Debug for UnwindContext<T, S>
1975where
1976    T: ReaderOffset,
1977    S: UnwindContextStorage<T>,
1978{
1979    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1980        f.debug_struct("UnwindContext")
1981            .field("stack", &self.stack)
1982            .field("initial_rule", &self.initial_rule)
1983            .field("is_initialized", &self.is_initialized)
1984            .finish()
1985    }
1986}
1987
1988impl<T, S> Default for UnwindContext<T, S>
1989where
1990    T: ReaderOffset,
1991    S: UnwindContextStorage<T>,
1992{
1993    fn default() -> Self {
1994        Self::new_in()
1995    }
1996}
1997
1998#[cfg(feature = "read")]
1999impl<T: ReaderOffset> UnwindContext<T> {
2000    /// Construct a new call frame unwinding context.
2001    pub fn new() -> Self {
2002        Self::new_in()
2003    }
2004}
2005
2006/// # Signal Safe Methods
2007///
2008/// These methods are guaranteed not to allocate, acquire locks, or perform any
2009/// other signal-unsafe operations, if an non-allocating storage is used.
2010impl<T, S> UnwindContext<T, S>
2011where
2012    T: ReaderOffset,
2013    S: UnwindContextStorage<T>,
2014{
2015    /// Construct a new call frame unwinding context.
2016    pub fn new_in() -> Self {
2017        let mut ctx = UnwindContext {
2018            stack: Default::default(),
2019            initial_rule: None,
2020            is_initialized: false,
2021        };
2022        ctx.reset();
2023        ctx
2024    }
2025
2026    /// Run the CIE's initial instructions and initialize this `UnwindContext`.
2027    fn initialize<Section, R>(
2028        &mut self,
2029        section: &Section,
2030        bases: &BaseAddresses,
2031        cie: &CommonInformationEntry<R>,
2032    ) -> Result<()>
2033    where
2034        R: Reader<Offset = T>,
2035        Section: UnwindSection<R>,
2036    {
2037        // Always reset because previous initialization failure may leave dirty state.
2038        self.reset();
2039
2040        let mut table = UnwindTable::new_for_cie(section, bases, self, cie);
2041        while table.next_row()?.is_some() {}
2042
2043        self.save_initial_rules()?;
2044        Ok(())
2045    }
2046
2047    fn reset(&mut self) {
2048        self.stack.clear();
2049        self.stack.try_push(UnwindTableRow::default()).unwrap();
2050        debug_assert!(self.stack[0].is_default());
2051        self.initial_rule = None;
2052        self.is_initialized = false;
2053    }
2054
2055    fn row(&self) -> &UnwindTableRow<T, S> {
2056        self.stack.last().unwrap()
2057    }
2058
2059    fn row_mut(&mut self) -> &mut UnwindTableRow<T, S> {
2060        self.stack.last_mut().unwrap()
2061    }
2062
2063    fn save_initial_rules(&mut self) -> Result<()> {
2064        debug_assert!(!self.is_initialized);
2065        self.initial_rule = match *self.stack.last().unwrap().registers.rules {
2066            // All rules are default (undefined). In this case just synthesize
2067            // an undefined rule.
2068            [] => Some((Register(0), RegisterRule::Undefined)),
2069            [ref rule] => Some(rule.clone()),
2070            _ => {
2071                let rules = self.stack.last().unwrap().clone();
2072                self.stack
2073                    .try_insert(0, rules)
2074                    .map_err(|_| Error::StackFull)?;
2075                None
2076            }
2077        };
2078        self.is_initialized = true;
2079        Ok(())
2080    }
2081
2082    fn start_address(&self) -> u64 {
2083        self.row().start_address
2084    }
2085
2086    fn set_start_address(&mut self, start_address: u64) {
2087        let row = self.row_mut();
2088        row.start_address = start_address;
2089    }
2090
2091    fn set_register_rule(&mut self, register: Register, rule: RegisterRule<T>) -> Result<()> {
2092        let row = self.row_mut();
2093        row.registers.set(register, rule)
2094    }
2095
2096    /// Returns `None` if we have not completed evaluation of a CIE's initial
2097    /// instructions.
2098    fn get_initial_rule(&self, register: Register) -> Option<RegisterRule<T>> {
2099        if !self.is_initialized {
2100            return None;
2101        }
2102        Some(match self.initial_rule {
2103            None => self.stack[0].registers.get(register),
2104            Some((r, ref rule)) if r == register => rule.clone(),
2105            _ => RegisterRule::Undefined,
2106        })
2107    }
2108
2109    fn set_cfa(&mut self, cfa: CfaRule<T>) {
2110        self.row_mut().cfa = cfa;
2111    }
2112
2113    fn cfa_mut(&mut self) -> &mut CfaRule<T> {
2114        &mut self.row_mut().cfa
2115    }
2116
2117    fn push_row(&mut self) -> Result<()> {
2118        let new_row = self.row().clone();
2119        self.stack.try_push(new_row).map_err(|_| Error::StackFull)
2120    }
2121
2122    fn pop_row(&mut self) -> Result<()> {
2123        let min_size = if self.is_initialized && self.initial_rule.is_none() {
2124            2
2125        } else {
2126            1
2127        };
2128        if self.stack.len() <= min_size {
2129            return Err(Error::PopWithEmptyStack);
2130        }
2131        self.stack.pop().unwrap();
2132        Ok(())
2133    }
2134}
2135
2136/// The `UnwindTable` iteratively evaluates a `FrameDescriptionEntry`'s
2137/// `CallFrameInstruction` program, yielding the each row one at a time.
2138///
2139/// > 6.4.1 Structure of Call Frame Information
2140/// >
2141/// > DWARF supports virtual unwinding by defining an architecture independent
2142/// > basis for recording how procedures save and restore registers during their
2143/// > lifetimes. This basis must be augmented on some machines with specific
2144/// > information that is defined by an architecture specific ABI authoring
2145/// > committee, a hardware vendor, or a compiler producer. The body defining a
2146/// > specific augmentation is referred to below as the “augmenter.”
2147/// >
2148/// > Abstractly, this mechanism describes a very large table that has the
2149/// > following structure:
2150/// >
2151/// > <table>
2152/// >   <tr>
2153/// >     <th>LOC</th><th>CFA</th><th>R0</th><th>R1</th><td>...</td><th>RN</th>
2154/// >   </tr>
2155/// >   <tr>
2156/// >     <th>L0</th> <td></td>   <td></td>  <td></td>  <td></td>   <td></td>
2157/// >   </tr>
2158/// >   <tr>
2159/// >     <th>L1</th> <td></td>   <td></td>  <td></td>  <td></td>   <td></td>
2160/// >   </tr>
2161/// >   <tr>
2162/// >     <td>...</td><td></td>   <td></td>  <td></td>  <td></td>   <td></td>
2163/// >   </tr>
2164/// >   <tr>
2165/// >     <th>LN</th> <td></td>   <td></td>  <td></td>  <td></td>   <td></td>
2166/// >   </tr>
2167/// > </table>
2168/// >
2169/// > The first column indicates an address for every location that contains code
2170/// > in a program. (In shared objects, this is an object-relative offset.) The
2171/// > remaining columns contain virtual unwinding rules that are associated with
2172/// > the indicated location.
2173/// >
2174/// > The CFA column defines the rule which computes the Canonical Frame Address
2175/// > value; it may be either a register and a signed offset that are added
2176/// > together, or a DWARF expression that is evaluated.
2177/// >
2178/// > The remaining columns are labeled by register number. This includes some
2179/// > registers that have special designation on some architectures such as the PC
2180/// > and the stack pointer register. (The actual mapping of registers for a
2181/// > particular architecture is defined by the augmenter.) The register columns
2182/// > contain rules that describe whether a given register has been saved and the
2183/// > rule to find the value for the register in the previous frame.
2184/// >
2185/// > ...
2186/// >
2187/// > This table would be extremely large if actually constructed as
2188/// > described. Most of the entries at any point in the table are identical to
2189/// > the ones above them. The whole table can be represented quite compactly by
2190/// > recording just the differences starting at the beginning address of each
2191/// > subroutine in the program.
2192#[derive(Debug)]
2193pub struct UnwindTable<'a, 'ctx, R, S = StoreOnHeap>
2194where
2195    R: Reader,
2196    S: UnwindContextStorage<R::Offset>,
2197{
2198    code_alignment_factor: Wrapping<u64>,
2199    data_alignment_factor: Wrapping<i64>,
2200    address_size: u8,
2201    next_start_address: u64,
2202    last_end_address: u64,
2203    returned_last_row: bool,
2204    current_row_valid: bool,
2205    instructions: CallFrameInstructionIter<'a, R>,
2206    ctx: &'ctx mut UnwindContext<R::Offset, S>,
2207}
2208
2209/// # Signal Safe Methods
2210///
2211/// These methods are guaranteed not to allocate, acquire locks, or perform any
2212/// other signal-unsafe operations.
2213impl<'a, 'ctx, R, S> UnwindTable<'a, 'ctx, R, S>
2214where
2215    R: Reader,
2216    S: UnwindContextStorage<R::Offset>,
2217{
2218    /// Construct a new `UnwindTable` for the given
2219    /// `FrameDescriptionEntry`'s CFI unwinding program.
2220    pub fn new<Section: UnwindSection<R>>(
2221        section: &'a Section,
2222        bases: &'a BaseAddresses,
2223        ctx: &'ctx mut UnwindContext<R::Offset, S>,
2224        fde: &FrameDescriptionEntry<R>,
2225    ) -> Result<Self> {
2226        ctx.initialize(section, bases, fde.cie())?;
2227        Ok(Self::new_for_fde(section, bases, ctx, fde))
2228    }
2229
2230    fn new_for_fde<Section: UnwindSection<R>>(
2231        section: &'a Section,
2232        bases: &'a BaseAddresses,
2233        ctx: &'ctx mut UnwindContext<R::Offset, S>,
2234        fde: &FrameDescriptionEntry<R>,
2235    ) -> Self {
2236        assert!(ctx.stack.len() >= 1);
2237        UnwindTable {
2238            code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()),
2239            data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()),
2240            address_size: fde.cie().address_size,
2241            next_start_address: fde.initial_address(),
2242            last_end_address: fde.end_address(),
2243            returned_last_row: false,
2244            current_row_valid: false,
2245            instructions: fde.instructions(section, bases),
2246            ctx,
2247        }
2248    }
2249
2250    fn new_for_cie<Section: UnwindSection<R>>(
2251        section: &'a Section,
2252        bases: &'a BaseAddresses,
2253        ctx: &'ctx mut UnwindContext<R::Offset, S>,
2254        cie: &CommonInformationEntry<R>,
2255    ) -> Self {
2256        assert!(ctx.stack.len() >= 1);
2257        UnwindTable {
2258            code_alignment_factor: Wrapping(cie.code_alignment_factor()),
2259            data_alignment_factor: Wrapping(cie.data_alignment_factor()),
2260            address_size: cie.address_size,
2261            next_start_address: 0,
2262            last_end_address: 0,
2263            returned_last_row: false,
2264            current_row_valid: false,
2265            instructions: cie.instructions(section, bases),
2266            ctx,
2267        }
2268    }
2269
2270    /// Evaluate call frame instructions until the next row of the table is
2271    /// completed, and return it.
2272    ///
2273    /// Unfortunately, this cannot be used with `FallibleIterator` because of
2274    /// the restricted lifetime of the yielded item.
2275    pub fn next_row(&mut self) -> Result<Option<&UnwindTableRow<R::Offset, S>>> {
2276        assert!(self.ctx.stack.len() >= 1);
2277        self.ctx.set_start_address(self.next_start_address);
2278        self.current_row_valid = false;
2279
2280        loop {
2281            match self.instructions.next() {
2282                Err(e) => return Err(e),
2283
2284                Ok(None) => {
2285                    if self.returned_last_row {
2286                        return Ok(None);
2287                    }
2288
2289                    let row = self.ctx.row_mut();
2290                    row.end_address = self.last_end_address;
2291
2292                    self.returned_last_row = true;
2293                    self.current_row_valid = true;
2294                    return Ok(Some(row));
2295                }
2296
2297                Ok(Some(instruction)) => {
2298                    if self.evaluate(instruction)? {
2299                        self.current_row_valid = true;
2300                        return Ok(Some(self.ctx.row()));
2301                    }
2302                }
2303            };
2304        }
2305    }
2306
2307    /// Returns the current row with the lifetime of the context.
2308    pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow<R::Offset, S>> {
2309        if self.current_row_valid {
2310            Some(self.ctx.row())
2311        } else {
2312            None
2313        }
2314    }
2315
2316    /// Evaluate one call frame instruction. Return `Ok(true)` if the row is
2317    /// complete, `Ok(false)` otherwise.
2318    fn evaluate(&mut self, instruction: CallFrameInstruction<R::Offset>) -> Result<bool> {
2319        use crate::CallFrameInstruction::*;
2320
2321        match instruction {
2322            // Instructions that complete the current row and advance the
2323            // address for the next row.
2324            SetLoc { address } => {
2325                if address < self.ctx.start_address() {
2326                    return Err(Error::InvalidAddressRange);
2327                }
2328
2329                self.next_start_address = address;
2330                self.ctx.row_mut().end_address = self.next_start_address;
2331                return Ok(true);
2332            }
2333            AdvanceLoc { delta } => {
2334                let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor;
2335                self.next_start_address = self
2336                    .ctx
2337                    .start_address()
2338                    .add_sized(delta.0, self.address_size)?;
2339                self.ctx.row_mut().end_address = self.next_start_address;
2340                return Ok(true);
2341            }
2342
2343            // Instructions that modify the CFA.
2344            DefCfa { register, offset } => {
2345                self.ctx.set_cfa(CfaRule::RegisterAndOffset {
2346                    register,
2347                    offset: offset as i64,
2348                });
2349            }
2350            DefCfaSf {
2351                register,
2352                factored_offset,
2353            } => {
2354                let data_align = self.data_alignment_factor;
2355                self.ctx.set_cfa(CfaRule::RegisterAndOffset {
2356                    register,
2357                    offset: (Wrapping(factored_offset) * data_align).0,
2358                });
2359            }
2360            DefCfaRegister { register } => {
2361                if let CfaRule::RegisterAndOffset {
2362                    register: ref mut reg,
2363                    ..
2364                } = *self.ctx.cfa_mut()
2365                {
2366                    *reg = register;
2367                } else {
2368                    return Err(Error::CfiInstructionInInvalidContext);
2369                }
2370            }
2371            DefCfaOffset { offset } => {
2372                if let CfaRule::RegisterAndOffset {
2373                    offset: ref mut off,
2374                    ..
2375                } = *self.ctx.cfa_mut()
2376                {
2377                    *off = offset as i64;
2378                } else {
2379                    return Err(Error::CfiInstructionInInvalidContext);
2380                }
2381            }
2382            DefCfaOffsetSf { factored_offset } => {
2383                if let CfaRule::RegisterAndOffset {
2384                    offset: ref mut off,
2385                    ..
2386                } = *self.ctx.cfa_mut()
2387                {
2388                    let data_align = self.data_alignment_factor;
2389                    *off = (Wrapping(factored_offset) * data_align).0;
2390                } else {
2391                    return Err(Error::CfiInstructionInInvalidContext);
2392                }
2393            }
2394            DefCfaExpression { expression } => {
2395                self.ctx.set_cfa(CfaRule::Expression(expression));
2396            }
2397
2398            // Instructions that define register rules.
2399            Undefined { register } => {
2400                self.ctx
2401                    .set_register_rule(register, RegisterRule::Undefined)?;
2402            }
2403            SameValue { register } => {
2404                self.ctx
2405                    .set_register_rule(register, RegisterRule::SameValue)?;
2406            }
2407            Offset {
2408                register,
2409                factored_offset,
2410            } => {
2411                let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
2412                self.ctx
2413                    .set_register_rule(register, RegisterRule::Offset(offset.0))?;
2414            }
2415            OffsetExtendedSf {
2416                register,
2417                factored_offset,
2418            } => {
2419                let offset = Wrapping(factored_offset) * self.data_alignment_factor;
2420                self.ctx
2421                    .set_register_rule(register, RegisterRule::Offset(offset.0))?;
2422            }
2423            ValOffset {
2424                register,
2425                factored_offset,
2426            } => {
2427                let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
2428                self.ctx
2429                    .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
2430            }
2431            ValOffsetSf {
2432                register,
2433                factored_offset,
2434            } => {
2435                let offset = Wrapping(factored_offset) * self.data_alignment_factor;
2436                self.ctx
2437                    .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
2438            }
2439            Register {
2440                dest_register,
2441                src_register,
2442            } => {
2443                self.ctx
2444                    .set_register_rule(dest_register, RegisterRule::Register(src_register))?;
2445            }
2446            Expression {
2447                register,
2448                expression,
2449            } => {
2450                let expression = RegisterRule::Expression(expression);
2451                self.ctx.set_register_rule(register, expression)?;
2452            }
2453            ValExpression {
2454                register,
2455                expression,
2456            } => {
2457                let expression = RegisterRule::ValExpression(expression);
2458                self.ctx.set_register_rule(register, expression)?;
2459            }
2460            Restore { register } => {
2461                let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) {
2462                    rule
2463                } else {
2464                    // Can't restore the initial rule when we are
2465                    // evaluating the initial rules!
2466                    return Err(Error::CfiInstructionInInvalidContext);
2467                };
2468
2469                self.ctx.set_register_rule(register, initial_rule)?;
2470            }
2471
2472            // Row push and pop instructions.
2473            RememberState => {
2474                self.ctx.push_row()?;
2475            }
2476            RestoreState => {
2477                // Pop state while preserving current location.
2478                let start_address = self.ctx.start_address();
2479                self.ctx.pop_row()?;
2480                self.ctx.set_start_address(start_address);
2481            }
2482
2483            // GNU Extension. Save the size somewhere so the unwinder can use
2484            // it when restoring IP
2485            ArgsSize { size } => {
2486                self.ctx.row_mut().saved_args_size = size;
2487            }
2488
2489            // AArch64 extension.
2490            NegateRaState => {
2491                let register = crate::AArch64::RA_SIGN_STATE;
2492                let value = match self.ctx.row().register(register) {
2493                    RegisterRule::Undefined => 0,
2494                    RegisterRule::Constant(value) => value,
2495                    _ => return Err(Error::CfiInstructionInInvalidContext),
2496                };
2497                self.ctx
2498                    .set_register_rule(register, RegisterRule::Constant(value ^ 1))?;
2499            }
2500
2501            // No operation.
2502            Nop => {}
2503        };
2504
2505        Ok(false)
2506    }
2507}
2508
2509// We tend to have very few register rules: usually only a couple. Even if we
2510// have a rule for every register, on x86-64 with SSE and everything we're
2511// talking about ~100 rules. So rather than keeping the rules in a hash map, or
2512// a vector indexed by register number (which would lead to filling lots of
2513// empty entries), we store them as a vec of (register number, register rule)
2514// pairs.
2515//
2516// Additionally, because every register's default rule is implicitly
2517// `RegisterRule::Undefined`, we never store a register's rule in this vec if it
2518// is undefined and save a little bit more space and do a little fewer
2519// comparisons that way.
2520//
2521// The maximum number of rules preallocated by libunwind is 97 for AArch64, 128
2522// for ARM, and even 188 for MIPS. It is extremely unlikely to encounter this
2523// many register rules in practice.
2524//
2525// See:
2526// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-x86_64/dwarf-config.h#L36
2527// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32
2528// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31
2529// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31
2530struct RegisterRuleMap<T, S = StoreOnHeap>
2531where
2532    T: ReaderOffset,
2533    S: UnwindContextStorage<T>,
2534{
2535    rules: ArrayVec<S::Rules>,
2536}
2537
2538impl<T, S> Debug for RegisterRuleMap<T, S>
2539where
2540    T: ReaderOffset,
2541    S: UnwindContextStorage<T>,
2542{
2543    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2544        f.debug_struct("RegisterRuleMap")
2545            .field("rules", &self.rules)
2546            .finish()
2547    }
2548}
2549
2550impl<T, S> Clone for RegisterRuleMap<T, S>
2551where
2552    T: ReaderOffset,
2553    S: UnwindContextStorage<T>,
2554{
2555    fn clone(&self) -> Self {
2556        Self {
2557            rules: self.rules.clone(),
2558        }
2559    }
2560}
2561
2562impl<T, S> Default for RegisterRuleMap<T, S>
2563where
2564    T: ReaderOffset,
2565    S: UnwindContextStorage<T>,
2566{
2567    fn default() -> Self {
2568        RegisterRuleMap {
2569            rules: Default::default(),
2570        }
2571    }
2572}
2573
2574/// # Signal Safe Methods
2575///
2576/// These methods are guaranteed not to allocate, acquire locks, or perform any
2577/// other signal-unsafe operations.
2578impl<T, S> RegisterRuleMap<T, S>
2579where
2580    T: ReaderOffset,
2581    S: UnwindContextStorage<T>,
2582{
2583    fn is_default(&self) -> bool {
2584        self.rules.is_empty()
2585    }
2586
2587    fn get(&self, register: Register) -> RegisterRule<T> {
2588        self.rules
2589            .iter()
2590            .find(|rule| rule.0 == register)
2591            .map(|r| {
2592                debug_assert!(r.1.is_defined());
2593                r.1.clone()
2594            })
2595            .unwrap_or(RegisterRule::Undefined)
2596    }
2597
2598    fn set(&mut self, register: Register, rule: RegisterRule<T>) -> Result<()> {
2599        if !rule.is_defined() {
2600            let idx = self
2601                .rules
2602                .iter()
2603                .enumerate()
2604                .find(|&(_, r)| r.0 == register)
2605                .map(|(i, _)| i);
2606            if let Some(idx) = idx {
2607                self.rules.swap_remove(idx);
2608            }
2609            return Ok(());
2610        }
2611
2612        for &mut (reg, ref mut old_rule) in &mut *self.rules {
2613            debug_assert!(old_rule.is_defined());
2614            if reg == register {
2615                *old_rule = rule;
2616                return Ok(());
2617            }
2618        }
2619
2620        self.rules
2621            .try_push((register, rule))
2622            .map_err(|_| Error::TooManyRegisterRules)
2623    }
2624
2625    fn iter(&self) -> RegisterRuleIter<'_, T> {
2626        RegisterRuleIter(self.rules.iter())
2627    }
2628}
2629
2630impl<'a, R, S> FromIterator<&'a (Register, RegisterRule<R>)> for RegisterRuleMap<R, S>
2631where
2632    R: 'a + ReaderOffset,
2633    S: UnwindContextStorage<R>,
2634{
2635    fn from_iter<T>(iter: T) -> Self
2636    where
2637        T: IntoIterator<Item = &'a (Register, RegisterRule<R>)>,
2638    {
2639        let iter = iter.into_iter();
2640        let mut rules = RegisterRuleMap::default();
2641        for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) {
2642            rules.set(reg, rule.clone()).expect(
2643                "This is only used in tests, impl isn't exposed publicly.
2644                         If you trip this, fix your test",
2645            );
2646        }
2647        rules
2648    }
2649}
2650
2651impl<T, S> PartialEq for RegisterRuleMap<T, S>
2652where
2653    T: ReaderOffset + PartialEq,
2654    S: UnwindContextStorage<T>,
2655{
2656    fn eq(&self, rhs: &Self) -> bool {
2657        for &(reg, ref rule) in &*self.rules {
2658            debug_assert!(rule.is_defined());
2659            if *rule != rhs.get(reg) {
2660                return false;
2661            }
2662        }
2663
2664        for &(reg, ref rhs_rule) in &*rhs.rules {
2665            debug_assert!(rhs_rule.is_defined());
2666            if *rhs_rule != self.get(reg) {
2667                return false;
2668            }
2669        }
2670
2671        true
2672    }
2673}
2674
2675impl<T, S> Eq for RegisterRuleMap<T, S>
2676where
2677    T: ReaderOffset + Eq,
2678    S: UnwindContextStorage<T>,
2679{
2680}
2681
2682/// An unordered iterator for register rules.
2683#[derive(Debug, Clone)]
2684pub struct RegisterRuleIter<'iter, T>(::core::slice::Iter<'iter, (Register, RegisterRule<T>)>)
2685where
2686    T: ReaderOffset;
2687
2688impl<'iter, T: ReaderOffset> Iterator for RegisterRuleIter<'iter, T> {
2689    type Item = &'iter (Register, RegisterRule<T>);
2690
2691    fn next(&mut self) -> Option<Self::Item> {
2692        self.0.next()
2693    }
2694}
2695
2696/// A row in the virtual unwind table that describes how to find the values of
2697/// the registers in the *previous* frame for a range of PC addresses.
2698#[derive(PartialEq, Eq)]
2699pub struct UnwindTableRow<T, S = StoreOnHeap>
2700where
2701    T: ReaderOffset,
2702    S: UnwindContextStorage<T>,
2703{
2704    start_address: u64,
2705    end_address: u64,
2706    saved_args_size: u64,
2707    cfa: CfaRule<T>,
2708    registers: RegisterRuleMap<T, S>,
2709}
2710
2711impl<T, S> Debug for UnwindTableRow<T, S>
2712where
2713    T: ReaderOffset,
2714    S: UnwindContextStorage<T>,
2715{
2716    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2717        f.debug_struct("UnwindTableRow")
2718            .field("start_address", &self.start_address)
2719            .field("end_address", &self.end_address)
2720            .field("saved_args_size", &self.saved_args_size)
2721            .field("cfa", &self.cfa)
2722            .field("registers", &self.registers)
2723            .finish()
2724    }
2725}
2726
2727impl<T, S> Clone for UnwindTableRow<T, S>
2728where
2729    T: ReaderOffset,
2730    S: UnwindContextStorage<T>,
2731{
2732    fn clone(&self) -> Self {
2733        Self {
2734            start_address: self.start_address,
2735            end_address: self.end_address,
2736            saved_args_size: self.saved_args_size,
2737            cfa: self.cfa.clone(),
2738            registers: self.registers.clone(),
2739        }
2740    }
2741}
2742
2743impl<T, S> Default for UnwindTableRow<T, S>
2744where
2745    T: ReaderOffset,
2746    S: UnwindContextStorage<T>,
2747{
2748    fn default() -> Self {
2749        UnwindTableRow {
2750            start_address: 0,
2751            end_address: 0,
2752            saved_args_size: 0,
2753            cfa: Default::default(),
2754            registers: Default::default(),
2755        }
2756    }
2757}
2758
2759impl<T, S> UnwindTableRow<T, S>
2760where
2761    T: ReaderOffset,
2762    S: UnwindContextStorage<T>,
2763{
2764    fn is_default(&self) -> bool {
2765        self.start_address == 0
2766            && self.end_address == 0
2767            && self.cfa.is_default()
2768            && self.registers.is_default()
2769    }
2770
2771    /// Get the starting PC address that this row applies to.
2772    pub fn start_address(&self) -> u64 {
2773        self.start_address
2774    }
2775
2776    /// Get the end PC address where this row's register rules become
2777    /// unapplicable.
2778    ///
2779    /// In other words, this row describes how to recover the last frame's
2780    /// registers for all PCs where `row.start_address() <= PC <
2781    /// row.end_address()`. This row does NOT describe how to recover registers
2782    /// when `PC == row.end_address()`.
2783    pub fn end_address(&self) -> u64 {
2784        self.end_address
2785    }
2786
2787    /// Return `true` if the given `address` is within this row's address range,
2788    /// `false` otherwise.
2789    pub fn contains(&self, address: u64) -> bool {
2790        self.start_address <= address && address < self.end_address
2791    }
2792
2793    /// Returns the amount of args currently on the stack.
2794    ///
2795    /// When unwinding, if the personality function requested a change in IP,
2796    /// the SP needs to be adjusted by saved_args_size.
2797    pub fn saved_args_size(&self) -> u64 {
2798        self.saved_args_size
2799    }
2800
2801    /// Get the canonical frame address (CFA) recovery rule for this row.
2802    pub fn cfa(&self) -> &CfaRule<T> {
2803        &self.cfa
2804    }
2805
2806    /// Get the register recovery rule for the given register number.
2807    ///
2808    /// The register number mapping is architecture dependent. For example, in
2809    /// the x86-64 ABI the register number mapping is defined in Figure 3.36:
2810    ///
2811    /// > Figure 3.36: DWARF Register Number Mapping
2812    /// >
2813    /// > <table>
2814    /// >   <tr><th>Register Name</th>                    <th>Number</th>  <th>Abbreviation</th></tr>
2815    /// >   <tr><td>General Purpose Register RAX</td>     <td>0</td>       <td>%rax</td></tr>
2816    /// >   <tr><td>General Purpose Register RDX</td>     <td>1</td>       <td>%rdx</td></tr>
2817    /// >   <tr><td>General Purpose Register RCX</td>     <td>2</td>       <td>%rcx</td></tr>
2818    /// >   <tr><td>General Purpose Register RBX</td>     <td>3</td>       <td>%rbx</td></tr>
2819    /// >   <tr><td>General Purpose Register RSI</td>     <td>4</td>       <td>%rsi</td></tr>
2820    /// >   <tr><td>General Purpose Register RDI</td>     <td>5</td>       <td>%rdi</td></tr>
2821    /// >   <tr><td>General Purpose Register RBP</td>     <td>6</td>       <td>%rbp</td></tr>
2822    /// >   <tr><td>Stack Pointer Register RSP</td>       <td>7</td>       <td>%rsp</td></tr>
2823    /// >   <tr><td>Extended Integer Registers 8-15</td>  <td>8-15</td>    <td>%r8-%r15</td></tr>
2824    /// >   <tr><td>Return Address RA</td>                <td>16</td>      <td></td></tr>
2825    /// >   <tr><td>Vector Registers 0–7</td>             <td>17-24</td>   <td>%xmm0–%xmm7</td></tr>
2826    /// >   <tr><td>Extended Vector Registers 8–15</td>   <td>25-32</td>   <td>%xmm8–%xmm15</td></tr>
2827    /// >   <tr><td>Floating Point Registers 0–7</td>     <td>33-40</td>   <td>%st0–%st7</td></tr>
2828    /// >   <tr><td>MMX Registers 0–7</td>                <td>41-48</td>   <td>%mm0–%mm7</td></tr>
2829    /// >   <tr><td>Flag Register</td>                    <td>49</td>      <td>%rFLAGS</td></tr>
2830    /// >   <tr><td>Segment Register ES</td>              <td>50</td>      <td>%es</td></tr>
2831    /// >   <tr><td>Segment Register CS</td>              <td>51</td>      <td>%cs</td></tr>
2832    /// >   <tr><td>Segment Register SS</td>              <td>52</td>      <td>%ss</td></tr>
2833    /// >   <tr><td>Segment Register DS</td>              <td>53</td>      <td>%ds</td></tr>
2834    /// >   <tr><td>Segment Register FS</td>              <td>54</td>      <td>%fs</td></tr>
2835    /// >   <tr><td>Segment Register GS</td>              <td>55</td>      <td>%gs</td></tr>
2836    /// >   <tr><td>Reserved</td>                         <td>56-57</td>   <td></td></tr>
2837    /// >   <tr><td>FS Base address</td>                  <td>58</td>      <td>%fs.base</td></tr>
2838    /// >   <tr><td>GS Base address</td>                  <td>59</td>      <td>%gs.base</td></tr>
2839    /// >   <tr><td>Reserved</td>                         <td>60-61</td>   <td></td></tr>
2840    /// >   <tr><td>Task Register</td>                    <td>62</td>      <td>%tr</td></tr>
2841    /// >   <tr><td>LDT Register</td>                     <td>63</td>      <td>%ldtr</td></tr>
2842    /// >   <tr><td>128-bit Media Control and Status</td> <td>64</td>      <td>%mxcsr</td></tr>
2843    /// >   <tr><td>x87 Control Word</td>                 <td>65</td>      <td>%fcw</td></tr>
2844    /// >   <tr><td>x87 Status Word</td>                  <td>66</td>      <td>%fsw</td></tr>
2845    /// >   <tr><td>Upper Vector Registers 16–31</td>     <td>67-82</td>   <td>%xmm16–%xmm31</td></tr>
2846    /// >   <tr><td>Reserved</td>                         <td>83-117</td>  <td></td></tr>
2847    /// >   <tr><td>Vector Mask Registers 0–7</td>        <td>118-125</td> <td>%k0–%k7</td></tr>
2848    /// >   <tr><td>Reserved</td>                         <td>126-129</td> <td></td></tr>
2849    /// > </table>
2850    pub fn register(&self, register: Register) -> RegisterRule<T> {
2851        self.registers.get(register)
2852    }
2853
2854    /// Iterate over all defined register `(number, rule)` pairs.
2855    ///
2856    /// The rules are not iterated in any guaranteed order. Any register that
2857    /// does not make an appearance in the iterator implicitly has the rule
2858    /// `RegisterRule::Undefined`.
2859    ///
2860    /// ```
2861    /// # use gimli::{EndianSlice, LittleEndian, UnwindTableRow};
2862    /// # fn foo<'input>(unwind_table_row: UnwindTableRow<usize>) {
2863    /// for &(register, ref rule) in unwind_table_row.registers() {
2864    ///     // ...
2865    ///     # drop(register); drop(rule);
2866    /// }
2867    /// # }
2868    /// ```
2869    pub fn registers(&self) -> RegisterRuleIter<'_, T> {
2870        self.registers.iter()
2871    }
2872}
2873
2874/// The canonical frame address (CFA) recovery rules.
2875#[derive(Clone, Debug, PartialEq, Eq)]
2876pub enum CfaRule<T: ReaderOffset> {
2877    /// The CFA is given offset from the given register's value.
2878    RegisterAndOffset {
2879        /// The register containing the base value.
2880        register: Register,
2881        /// The offset from the register's base value.
2882        offset: i64,
2883    },
2884    /// The CFA is obtained by evaluating a DWARF expression program.
2885    Expression(UnwindExpression<T>),
2886}
2887
2888impl<T: ReaderOffset> Default for CfaRule<T> {
2889    fn default() -> Self {
2890        CfaRule::RegisterAndOffset {
2891            register: Register(0),
2892            offset: 0,
2893        }
2894    }
2895}
2896
2897impl<T: ReaderOffset> CfaRule<T> {
2898    fn is_default(&self) -> bool {
2899        match *self {
2900            CfaRule::RegisterAndOffset { register, offset } => {
2901                register == Register(0) && offset == 0
2902            }
2903            _ => false,
2904        }
2905    }
2906}
2907
2908/// An entry in the abstract CFI table that describes how to find the value of a
2909/// register.
2910///
2911/// "The register columns contain rules that describe whether a given register
2912/// has been saved and the rule to find the value for the register in the
2913/// previous frame."
2914#[derive(Clone, Debug, PartialEq, Eq)]
2915#[non_exhaustive]
2916pub enum RegisterRule<T: ReaderOffset> {
2917    /// > A register that has this rule has no recoverable value in the previous
2918    /// > frame. (By convention, it is not preserved by a callee.)
2919    Undefined,
2920
2921    /// > This register has not been modified from the previous frame. (By
2922    /// > convention, it is preserved by the callee, but the callee has not
2923    /// > modified it.)
2924    SameValue,
2925
2926    /// "The previous value of this register is saved at the address CFA+N where
2927    /// CFA is the current CFA value and N is a signed offset."
2928    Offset(i64),
2929
2930    /// "The previous value of this register is the value CFA+N where CFA is the
2931    /// current CFA value and N is a signed offset."
2932    ValOffset(i64),
2933
2934    /// "The previous value of this register is stored in another register
2935    /// numbered R."
2936    Register(Register),
2937
2938    /// "The previous value of this register is located at the address produced
2939    /// by executing the DWARF expression."
2940    Expression(UnwindExpression<T>),
2941
2942    /// "The previous value of this register is the value produced by executing
2943    /// the DWARF expression."
2944    ValExpression(UnwindExpression<T>),
2945
2946    /// "The rule is defined externally to this specification by the augmenter."
2947    Architectural,
2948
2949    /// This is a pseudo-register with a constant value.
2950    Constant(u64),
2951}
2952
2953impl<T: ReaderOffset> RegisterRule<T> {
2954    fn is_defined(&self) -> bool {
2955        !matches!(*self, RegisterRule::Undefined)
2956    }
2957}
2958
2959/// A parsed call frame instruction.
2960#[derive(Clone, Debug, PartialEq, Eq)]
2961#[non_exhaustive]
2962pub enum CallFrameInstruction<T: ReaderOffset> {
2963    // 6.4.2.1 Row Creation Methods
2964    /// > 1. DW_CFA_set_loc
2965    /// >
2966    /// > The DW_CFA_set_loc instruction takes a single operand that represents
2967    /// > a target address. The required action is to create a new table row
2968    /// > using the specified address as the location. All other values in the
2969    /// > new row are initially identical to the current row. The new location
2970    /// > value is always greater than the current one. If the segment_size
2971    /// > field of this FDE's CIE is non- zero, the initial location is preceded
2972    /// > by a segment selector of the given length.
2973    SetLoc {
2974        /// The target address.
2975        address: u64,
2976    },
2977
2978    /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and
2979    /// `DW_CFA_advance_loc{1,2,4}`.
2980    ///
2981    /// > 2. DW_CFA_advance_loc
2982    /// >
2983    /// > The DW_CFA_advance instruction takes a single operand (encoded with
2984    /// > the opcode) that represents a constant delta. The required action is
2985    /// > to create a new table row with a location value that is computed by
2986    /// > taking the current entry’s location value and adding the value of
2987    /// > delta * code_alignment_factor. All other values in the new row are
2988    /// > initially identical to the current row.
2989    AdvanceLoc {
2990        /// The delta to be added to the current address.
2991        delta: u32,
2992    },
2993
2994    // 6.4.2.2 CFA Definition Methods
2995    /// > 1. DW_CFA_def_cfa
2996    /// >
2997    /// > The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands
2998    /// > representing a register number and a (non-factored) offset. The
2999    /// > required action is to define the current CFA rule to use the provided
3000    /// > register and offset.
3001    DefCfa {
3002        /// The target register's number.
3003        register: Register,
3004        /// The non-factored offset.
3005        offset: u64,
3006    },
3007
3008    /// > 2. DW_CFA_def_cfa_sf
3009    /// >
3010    /// > The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned
3011    /// > LEB128 value representing a register number and a signed LEB128
3012    /// > factored offset. This instruction is identical to DW_CFA_def_cfa
3013    /// > except that the second operand is signed and factored. The resulting
3014    /// > offset is factored_offset * data_alignment_factor.
3015    DefCfaSf {
3016        /// The target register's number.
3017        register: Register,
3018        /// The factored offset.
3019        factored_offset: i64,
3020    },
3021
3022    /// > 3. DW_CFA_def_cfa_register
3023    /// >
3024    /// > The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128
3025    /// > operand representing a register number. The required action is to
3026    /// > define the current CFA rule to use the provided register (but to keep
3027    /// > the old offset). This operation is valid only if the current CFA rule
3028    /// > is defined to use a register and offset.
3029    DefCfaRegister {
3030        /// The target register's number.
3031        register: Register,
3032    },
3033
3034    /// > 4. DW_CFA_def_cfa_offset
3035    /// >
3036    /// > The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128
3037    /// > operand representing a (non-factored) offset. The required action is
3038    /// > to define the current CFA rule to use the provided offset (but to keep
3039    /// > the old register). This operation is valid only if the current CFA
3040    /// > rule is defined to use a register and offset.
3041    DefCfaOffset {
3042        /// The non-factored offset.
3043        offset: u64,
3044    },
3045
3046    /// > 5. DW_CFA_def_cfa_offset_sf
3047    /// >
3048    /// > The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand
3049    /// > representing a factored offset. This instruction is identical to
3050    /// > DW_CFA_def_cfa_offset except that the operand is signed and
3051    /// > factored. The resulting offset is factored_offset *
3052    /// > data_alignment_factor. This operation is valid only if the current CFA
3053    /// > rule is defined to use a register and offset.
3054    DefCfaOffsetSf {
3055        /// The factored offset.
3056        factored_offset: i64,
3057    },
3058
3059    /// > 6. DW_CFA_def_cfa_expression
3060    /// >
3061    /// > The DW_CFA_def_cfa_expression instruction takes a single operand
3062    /// > encoded as a DW_FORM_exprloc value representing a DWARF
3063    /// > expression. The required action is to establish that expression as the
3064    /// > means by which the current CFA is computed.
3065    DefCfaExpression {
3066        /// The location of the DWARF expression.
3067        expression: UnwindExpression<T>,
3068    },
3069
3070    // 6.4.2.3 Register Rule Instructions
3071    /// > 1. DW_CFA_undefined
3072    /// >
3073    /// > The DW_CFA_undefined instruction takes a single unsigned LEB128
3074    /// > operand that represents a register number. The required action is to
3075    /// > set the rule for the specified register to “undefined.”
3076    Undefined {
3077        /// The target register's number.
3078        register: Register,
3079    },
3080
3081    /// > 2. DW_CFA_same_value
3082    /// >
3083    /// > The DW_CFA_same_value instruction takes a single unsigned LEB128
3084    /// > operand that represents a register number. The required action is to
3085    /// > set the rule for the specified register to “same value.”
3086    SameValue {
3087        /// The target register's number.
3088        register: Register,
3089    },
3090
3091    /// The `Offset` instruction represents both `DW_CFA_offset` and
3092    /// `DW_CFA_offset_extended`.
3093    ///
3094    /// > 3. DW_CFA_offset
3095    /// >
3096    /// > The DW_CFA_offset instruction takes two operands: a register number
3097    /// > (encoded with the opcode) and an unsigned LEB128 constant representing
3098    /// > a factored offset. The required action is to change the rule for the
3099    /// > register indicated by the register number to be an offset(N) rule
3100    /// > where the value of N is factored offset * data_alignment_factor.
3101    Offset {
3102        /// The target register's number.
3103        register: Register,
3104        /// The factored offset.
3105        factored_offset: u64,
3106    },
3107
3108    /// > 5. DW_CFA_offset_extended_sf
3109    /// >
3110    /// > The DW_CFA_offset_extended_sf instruction takes two operands: an
3111    /// > unsigned LEB128 value representing a register number and a signed
3112    /// > LEB128 factored offset. This instruction is identical to
3113    /// > DW_CFA_offset_extended except that the second operand is signed and
3114    /// > factored. The resulting offset is factored_offset *
3115    /// > data_alignment_factor.
3116    OffsetExtendedSf {
3117        /// The target register's number.
3118        register: Register,
3119        /// The factored offset.
3120        factored_offset: i64,
3121    },
3122
3123    /// > 6. DW_CFA_val_offset
3124    /// >
3125    /// > The DW_CFA_val_offset instruction takes two unsigned LEB128 operands
3126    /// > representing a register number and a factored offset. The required
3127    /// > action is to change the rule for the register indicated by the
3128    /// > register number to be a val_offset(N) rule where the value of N is
3129    /// > factored_offset * data_alignment_factor.
3130    ValOffset {
3131        /// The target register's number.
3132        register: Register,
3133        /// The factored offset.
3134        factored_offset: u64,
3135    },
3136
3137    /// > 7. DW_CFA_val_offset_sf
3138    /// >
3139    /// > The DW_CFA_val_offset_sf instruction takes two operands: an unsigned
3140    /// > LEB128 value representing a register number and a signed LEB128
3141    /// > factored offset. This instruction is identical to DW_CFA_val_offset
3142    /// > except that the second operand is signed and factored. The resulting
3143    /// > offset is factored_offset * data_alignment_factor.
3144    ValOffsetSf {
3145        /// The target register's number.
3146        register: Register,
3147        /// The factored offset.
3148        factored_offset: i64,
3149    },
3150
3151    /// > 8. DW_CFA_register
3152    /// >
3153    /// > The DW_CFA_register instruction takes two unsigned LEB128 operands
3154    /// > representing register numbers. The required action is to set the rule
3155    /// > for the first register to be register(R) where R is the second
3156    /// > register.
3157    Register {
3158        /// The number of the register whose rule is being changed.
3159        dest_register: Register,
3160        /// The number of the register where the other register's value can be
3161        /// found.
3162        src_register: Register,
3163    },
3164
3165    /// > 9. DW_CFA_expression
3166    /// >
3167    /// > The DW_CFA_expression instruction takes two operands: an unsigned
3168    /// > LEB128 value representing a register number, and a DW_FORM_block value
3169    /// > representing a DWARF expression. The required action is to change the
3170    /// > rule for the register indicated by the register number to be an
3171    /// > expression(E) rule where E is the DWARF expression. That is, the DWARF
3172    /// > expression computes the address. The value of the CFA is pushed on the
3173    /// > DWARF evaluation stack prior to execution of the DWARF expression.
3174    Expression {
3175        /// The target register's number.
3176        register: Register,
3177        /// The location of the DWARF expression.
3178        expression: UnwindExpression<T>,
3179    },
3180
3181    /// > 10. DW_CFA_val_expression
3182    /// >
3183    /// > The DW_CFA_val_expression instruction takes two operands: an unsigned
3184    /// > LEB128 value representing a register number, and a DW_FORM_block value
3185    /// > representing a DWARF expression. The required action is to change the
3186    /// > rule for the register indicated by the register number to be a
3187    /// > val_expression(E) rule where E is the DWARF expression. That is, the
3188    /// > DWARF expression computes the value of the given register. The value
3189    /// > of the CFA is pushed on the DWARF evaluation stack prior to execution
3190    /// > of the DWARF expression.
3191    ValExpression {
3192        /// The target register's number.
3193        register: Register,
3194        /// The location of the DWARF expression.
3195        expression: UnwindExpression<T>,
3196    },
3197
3198    /// The `Restore` instruction represents both `DW_CFA_restore` and
3199    /// `DW_CFA_restore_extended`.
3200    ///
3201    /// > 11. DW_CFA_restore
3202    /// >
3203    /// > The DW_CFA_restore instruction takes a single operand (encoded with
3204    /// > the opcode) that represents a register number. The required action is
3205    /// > to change the rule for the indicated register to the rule assigned it
3206    /// > by the initial_instructions in the CIE.
3207    Restore {
3208        /// The register to be reset.
3209        register: Register,
3210    },
3211
3212    // 6.4.2.4 Row State Instructions
3213    /// > 1. DW_CFA_remember_state
3214    /// >
3215    /// > The DW_CFA_remember_state instruction takes no operands. The required
3216    /// > action is to push the set of rules for every register onto an implicit
3217    /// > stack.
3218    RememberState,
3219
3220    /// > 2. DW_CFA_restore_state
3221    /// >
3222    /// > The DW_CFA_restore_state instruction takes no operands. The required
3223    /// > action is to pop the set of rules off the implicit stack and place
3224    /// > them in the current row.
3225    RestoreState,
3226
3227    /// > DW_CFA_GNU_args_size
3228    /// >
3229    /// > GNU Extension
3230    /// >
3231    /// > The DW_CFA_GNU_args_size instruction takes an unsigned LEB128 operand
3232    /// > representing an argument size. This instruction specifies the total of
3233    /// > the size of the arguments which have been pushed onto the stack.
3234    ArgsSize {
3235        /// The size of the arguments which have been pushed onto the stack
3236        size: u64,
3237    },
3238
3239    /// > DW_CFA_AARCH64_negate_ra_state
3240    /// >
3241    /// > AArch64 Extension
3242    /// >
3243    /// > The DW_CFA_AARCH64_negate_ra_state operation negates bit 0 of the
3244    /// > RA_SIGN_STATE pseudo-register. It does not take any operands. The
3245    /// > DW_CFA_AARCH64_negate_ra_state must not be mixed with other DWARF Register
3246    /// > Rule Instructions on the RA_SIGN_STATE pseudo-register in one Common
3247    /// > Information Entry (CIE) and Frame Descriptor Entry (FDE) program sequence.
3248    NegateRaState,
3249
3250    // 6.4.2.5 Padding Instruction
3251    /// > 1. DW_CFA_nop
3252    /// >
3253    /// > The DW_CFA_nop instruction has no operands and no required actions. It
3254    /// > is used as padding to make a CIE or FDE an appropriate size.
3255    Nop,
3256}
3257
3258const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000;
3259const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK;
3260
3261impl<T: ReaderOffset> CallFrameInstruction<T> {
3262    fn parse<R: Reader<Offset = T>>(
3263        input: &mut R,
3264        address_encoding: Option<DwEhPe>,
3265        parameters: &PointerEncodingParameters<'_, R>,
3266        vendor: Vendor,
3267    ) -> Result<CallFrameInstruction<T>> {
3268        let instruction = input.read_u8()?;
3269        let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK;
3270
3271        if high_bits == constants::DW_CFA_advance_loc.0 {
3272            let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK;
3273            return Ok(CallFrameInstruction::AdvanceLoc {
3274                delta: u32::from(delta),
3275            });
3276        }
3277
3278        if high_bits == constants::DW_CFA_offset.0 {
3279            let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3280            let offset = input.read_uleb128()?;
3281            return Ok(CallFrameInstruction::Offset {
3282                register,
3283                factored_offset: offset,
3284            });
3285        }
3286
3287        if high_bits == constants::DW_CFA_restore.0 {
3288            let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3289            return Ok(CallFrameInstruction::Restore { register });
3290        }
3291
3292        debug_assert_eq!(high_bits, 0);
3293        let instruction = constants::DwCfa(instruction);
3294
3295        match instruction {
3296            constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop),
3297
3298            constants::DW_CFA_set_loc => {
3299                let address = if let Some(encoding) = address_encoding {
3300                    parse_encoded_pointer(encoding, parameters, input)?.direct()?
3301                } else {
3302                    input.read_address(parameters.address_size)?
3303                };
3304                Ok(CallFrameInstruction::SetLoc { address })
3305            }
3306
3307            constants::DW_CFA_advance_loc1 => {
3308                let delta = input.read_u8()?;
3309                Ok(CallFrameInstruction::AdvanceLoc {
3310                    delta: u32::from(delta),
3311                })
3312            }
3313
3314            constants::DW_CFA_advance_loc2 => {
3315                let delta = input.read_u16()?;
3316                Ok(CallFrameInstruction::AdvanceLoc {
3317                    delta: u32::from(delta),
3318                })
3319            }
3320
3321            constants::DW_CFA_advance_loc4 => {
3322                let delta = input.read_u32()?;
3323                Ok(CallFrameInstruction::AdvanceLoc { delta })
3324            }
3325
3326            constants::DW_CFA_offset_extended => {
3327                let register = input.read_uleb128().and_then(Register::from_u64)?;
3328                let offset = input.read_uleb128()?;
3329                Ok(CallFrameInstruction::Offset {
3330                    register,
3331                    factored_offset: offset,
3332                })
3333            }
3334
3335            constants::DW_CFA_restore_extended => {
3336                let register = input.read_uleb128().and_then(Register::from_u64)?;
3337                Ok(CallFrameInstruction::Restore { register })
3338            }
3339
3340            constants::DW_CFA_undefined => {
3341                let register = input.read_uleb128().and_then(Register::from_u64)?;
3342                Ok(CallFrameInstruction::Undefined { register })
3343            }
3344
3345            constants::DW_CFA_same_value => {
3346                let register = input.read_uleb128().and_then(Register::from_u64)?;
3347                Ok(CallFrameInstruction::SameValue { register })
3348            }
3349
3350            constants::DW_CFA_register => {
3351                let dest = input.read_uleb128().and_then(Register::from_u64)?;
3352                let src = input.read_uleb128().and_then(Register::from_u64)?;
3353                Ok(CallFrameInstruction::Register {
3354                    dest_register: dest,
3355                    src_register: src,
3356                })
3357            }
3358
3359            constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState),
3360
3361            constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState),
3362
3363            constants::DW_CFA_def_cfa => {
3364                let register = input.read_uleb128().and_then(Register::from_u64)?;
3365                let offset = input.read_uleb128()?;
3366                Ok(CallFrameInstruction::DefCfa { register, offset })
3367            }
3368
3369            constants::DW_CFA_def_cfa_register => {
3370                let register = input.read_uleb128().and_then(Register::from_u64)?;
3371                Ok(CallFrameInstruction::DefCfaRegister { register })
3372            }
3373
3374            constants::DW_CFA_def_cfa_offset => {
3375                let offset = input.read_uleb128()?;
3376                Ok(CallFrameInstruction::DefCfaOffset { offset })
3377            }
3378
3379            constants::DW_CFA_def_cfa_expression => {
3380                let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3381                let offset = input.offset_from(parameters.section);
3382                input.skip(length)?;
3383                Ok(CallFrameInstruction::DefCfaExpression {
3384                    expression: UnwindExpression { offset, length },
3385                })
3386            }
3387
3388            constants::DW_CFA_expression => {
3389                let register = input.read_uleb128().and_then(Register::from_u64)?;
3390                let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3391                let offset = input.offset_from(parameters.section);
3392                input.skip(length)?;
3393                Ok(CallFrameInstruction::Expression {
3394                    register,
3395                    expression: UnwindExpression { offset, length },
3396                })
3397            }
3398
3399            constants::DW_CFA_offset_extended_sf => {
3400                let register = input.read_uleb128().and_then(Register::from_u64)?;
3401                let offset = input.read_sleb128()?;
3402                Ok(CallFrameInstruction::OffsetExtendedSf {
3403                    register,
3404                    factored_offset: offset,
3405                })
3406            }
3407
3408            constants::DW_CFA_def_cfa_sf => {
3409                let register = input.read_uleb128().and_then(Register::from_u64)?;
3410                let offset = input.read_sleb128()?;
3411                Ok(CallFrameInstruction::DefCfaSf {
3412                    register,
3413                    factored_offset: offset,
3414                })
3415            }
3416
3417            constants::DW_CFA_def_cfa_offset_sf => {
3418                let offset = input.read_sleb128()?;
3419                Ok(CallFrameInstruction::DefCfaOffsetSf {
3420                    factored_offset: offset,
3421                })
3422            }
3423
3424            constants::DW_CFA_val_offset => {
3425                let register = input.read_uleb128().and_then(Register::from_u64)?;
3426                let offset = input.read_uleb128()?;
3427                Ok(CallFrameInstruction::ValOffset {
3428                    register,
3429                    factored_offset: offset,
3430                })
3431            }
3432
3433            constants::DW_CFA_val_offset_sf => {
3434                let register = input.read_uleb128().and_then(Register::from_u64)?;
3435                let offset = input.read_sleb128()?;
3436                Ok(CallFrameInstruction::ValOffsetSf {
3437                    register,
3438                    factored_offset: offset,
3439                })
3440            }
3441
3442            constants::DW_CFA_val_expression => {
3443                let register = input.read_uleb128().and_then(Register::from_u64)?;
3444                let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3445                let offset = input.offset_from(parameters.section);
3446                input.skip(length)?;
3447                Ok(CallFrameInstruction::ValExpression {
3448                    register,
3449                    expression: UnwindExpression { offset, length },
3450                })
3451            }
3452
3453            constants::DW_CFA_GNU_args_size => {
3454                let size = input.read_uleb128()?;
3455                Ok(CallFrameInstruction::ArgsSize { size })
3456            }
3457
3458            constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => {
3459                Ok(CallFrameInstruction::NegateRaState)
3460            }
3461
3462            otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
3463        }
3464    }
3465}
3466
3467/// A lazy iterator parsing call frame instructions.
3468///
3469/// Can be [used with
3470/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
3471#[derive(Clone, Debug)]
3472pub struct CallFrameInstructionIter<'a, R: Reader> {
3473    input: R,
3474    address_encoding: Option<constants::DwEhPe>,
3475    parameters: PointerEncodingParameters<'a, R>,
3476    vendor: Vendor,
3477}
3478
3479impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
3480    /// Parse the next call frame instruction.
3481    pub fn next(&mut self) -> Result<Option<CallFrameInstruction<R::Offset>>> {
3482        if self.input.is_empty() {
3483            return Ok(None);
3484        }
3485
3486        match CallFrameInstruction::parse(
3487            &mut self.input,
3488            self.address_encoding,
3489            &self.parameters,
3490            self.vendor,
3491        ) {
3492            Ok(instruction) => Ok(Some(instruction)),
3493            Err(e) => {
3494                self.input.empty();
3495                Err(e)
3496            }
3497        }
3498    }
3499}
3500
3501#[cfg(feature = "fallible-iterator")]
3502impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> {
3503    type Item = CallFrameInstruction<R::Offset>;
3504    type Error = Error;
3505
3506    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
3507        CallFrameInstructionIter::next(self)
3508    }
3509}
3510
3511/// The location of a DWARF expression within an unwind section.
3512///
3513/// This is stored as an offset and length within the section instead of as a
3514/// `Reader` to avoid lifetime issues when reusing [`UnwindContext`].
3515///
3516/// # Example
3517/// ```
3518/// # use gimli::{EhFrame, EndianSlice, NativeEndian, Error, FrameDescriptionEntry, UnwindExpression, EvaluationResult};
3519/// # fn foo() -> Result<(), Error> {
3520/// # let eh_frame: EhFrame<EndianSlice<NativeEndian>> = unreachable!();
3521/// # let fde: FrameDescriptionEntry<EndianSlice<NativeEndian>> = unimplemented!();
3522/// # let unwind_expression: UnwindExpression<_> = unimplemented!();
3523/// let expression = unwind_expression.get(&eh_frame)?;
3524/// let mut evaluation = expression.evaluation(fde.cie().encoding());
3525/// let mut result = evaluation.evaluate()?;
3526/// loop {
3527///   match result {
3528///      EvaluationResult::Complete => break,
3529///      // Provide information to the evaluation.
3530///      _ => { unimplemented!()}
3531///   }
3532/// }
3533/// let value = evaluation.value_result();
3534/// # Ok(())
3535/// # }
3536/// ```
3537#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3538pub struct UnwindExpression<T: ReaderOffset> {
3539    /// The offset of the expression within the section.
3540    pub offset: T,
3541    /// The length of the expression.
3542    pub length: T,
3543}
3544
3545impl<T: ReaderOffset> UnwindExpression<T> {
3546    /// Get the expression from the section.
3547    ///
3548    /// The offset and length were previously validated when the
3549    /// `UnwindExpression` was created, so this should not fail.
3550    pub fn get<R, S>(&self, section: &S) -> Result<Expression<R>>
3551    where
3552        R: Reader<Offset = T>,
3553        S: UnwindSection<R>,
3554    {
3555        let input = &mut section.section().clone();
3556        input.skip(self.offset)?;
3557        let data = input.split(self.length)?;
3558        Ok(Expression(data))
3559    }
3560}
3561
3562/// Parse a `DW_EH_PE_*` pointer encoding.
3563#[doc(hidden)]
3564#[inline]
3565fn parse_pointer_encoding<R: Reader>(input: &mut R) -> Result<constants::DwEhPe> {
3566    let eh_pe = input.read_u8()?;
3567    let eh_pe = constants::DwEhPe(eh_pe);
3568
3569    if eh_pe.is_valid_encoding() {
3570        Ok(eh_pe)
3571    } else {
3572        Err(Error::UnknownPointerEncoding(eh_pe))
3573    }
3574}
3575
3576/// A decoded pointer.
3577#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3578pub enum Pointer {
3579    /// This value is the decoded pointer value.
3580    Direct(u64),
3581
3582    /// This value is *not* the pointer value, but points to the address of
3583    /// where the real pointer value lives. In other words, deref this pointer
3584    /// to get the real pointer value.
3585    ///
3586    /// Chase this pointer at your own risk: do you trust the DWARF data it came
3587    /// from?
3588    Indirect(u64),
3589}
3590
3591impl Default for Pointer {
3592    #[inline]
3593    fn default() -> Self {
3594        Pointer::Direct(0)
3595    }
3596}
3597
3598impl Pointer {
3599    #[inline]
3600    fn new(encoding: constants::DwEhPe, address: u64) -> Pointer {
3601        if encoding.is_indirect() {
3602            Pointer::Indirect(address)
3603        } else {
3604            Pointer::Direct(address)
3605        }
3606    }
3607
3608    /// Return the direct pointer value.
3609    #[inline]
3610    pub fn direct(self) -> Result<u64> {
3611        match self {
3612            Pointer::Direct(p) => Ok(p),
3613            Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding),
3614        }
3615    }
3616
3617    /// Return the pointer value, discarding indirectness information.
3618    #[inline]
3619    pub fn pointer(self) -> u64 {
3620        match self {
3621            Pointer::Direct(p) | Pointer::Indirect(p) => p,
3622        }
3623    }
3624}
3625
3626#[derive(Clone, Debug)]
3627struct PointerEncodingParameters<'a, R: Reader> {
3628    bases: &'a SectionBaseAddresses,
3629    func_base: Option<u64>,
3630    address_size: u8,
3631    section: &'a R,
3632}
3633
3634fn parse_encoded_pointer<R: Reader>(
3635    encoding: constants::DwEhPe,
3636    parameters: &PointerEncodingParameters<'_, R>,
3637    input: &mut R,
3638) -> Result<Pointer> {
3639    // TODO: check this once only in parse_pointer_encoding
3640    if !encoding.is_valid_encoding() {
3641        return Err(Error::UnknownPointerEncoding(encoding));
3642    }
3643
3644    if encoding == constants::DW_EH_PE_omit {
3645        return Err(Error::CannotParseOmitPointerEncoding);
3646    }
3647
3648    let base = match encoding.application() {
3649        constants::DW_EH_PE_absptr => 0,
3650        constants::DW_EH_PE_pcrel => {
3651            if let Some(section_base) = parameters.bases.section {
3652                let offset_from_section = input.offset_from(parameters.section);
3653                section_base
3654                    .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size)
3655            } else {
3656                return Err(Error::PcRelativePointerButSectionBaseIsUndefined);
3657            }
3658        }
3659        constants::DW_EH_PE_textrel => {
3660            if let Some(text) = parameters.bases.text {
3661                text
3662            } else {
3663                return Err(Error::TextRelativePointerButTextBaseIsUndefined);
3664            }
3665        }
3666        constants::DW_EH_PE_datarel => {
3667            if let Some(data) = parameters.bases.data {
3668                data
3669            } else {
3670                return Err(Error::DataRelativePointerButDataBaseIsUndefined);
3671            }
3672        }
3673        constants::DW_EH_PE_funcrel => {
3674            if let Some(func) = parameters.func_base {
3675                func
3676            } else {
3677                return Err(Error::FuncRelativePointerInBadContext);
3678            }
3679        }
3680        constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding),
3681        _ => unreachable!(),
3682    };
3683
3684    let offset = parse_encoded_value(encoding, parameters, input)?;
3685    Ok(Pointer::new(
3686        encoding,
3687        base.wrapping_add_sized(offset, parameters.address_size),
3688    ))
3689}
3690
3691fn parse_encoded_value<R: Reader>(
3692    encoding: constants::DwEhPe,
3693    parameters: &PointerEncodingParameters<'_, R>,
3694    input: &mut R,
3695) -> Result<u64> {
3696    match encoding.format() {
3697        // Unsigned variants.
3698        constants::DW_EH_PE_absptr => input.read_address(parameters.address_size),
3699        constants::DW_EH_PE_uleb128 => input.read_uleb128(),
3700        constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from),
3701        constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from),
3702        constants::DW_EH_PE_udata8 => input.read_u64(),
3703
3704        // Signed variants. Here we sign extend the values (happens by
3705        // default when casting a signed integer to a larger range integer
3706        // in Rust), return them as u64, and rely on wrapping addition to do
3707        // the right thing when adding these offsets to their bases.
3708        constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64),
3709        constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64),
3710        constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64),
3711        constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64),
3712
3713        // That was all of the valid encoding formats.
3714        _ => unreachable!(),
3715    }
3716}
3717
3718#[cfg(test)]
3719mod tests {
3720    use super::*;
3721    use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext};
3722    use crate::common::Format;
3723    use crate::constants;
3724    use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian};
3725    use crate::read::{
3726        EndianSlice, Error, Pointer, ReaderOffsetId, Result, Section as ReadSection,
3727    };
3728    use crate::test_util::GimliSectionMethods;
3729    use alloc::boxed::Box;
3730    use alloc::vec::Vec;
3731    use core::marker::PhantomData;
3732    use core::mem;
3733    use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum};
3734
3735    // Ensure each test tries to read the same section kind that it wrote.
3736    #[derive(Clone, Copy)]
3737    struct SectionKind<Section>(PhantomData<Section>);
3738
3739    impl<T> SectionKind<T> {
3740        fn endian<'input, E>(self) -> Endian
3741        where
3742            E: Endianity,
3743            T: UnwindSection<EndianSlice<'input, E>>,
3744            T::Offset: UnwindOffset<usize>,
3745        {
3746            if E::default().is_big_endian() {
3747                Endian::Big
3748            } else {
3749                Endian::Little
3750            }
3751        }
3752
3753        fn section<'input, E>(self, contents: &'input [u8]) -> T
3754        where
3755            E: Endianity,
3756            T: UnwindSection<EndianSlice<'input, E>> + ReadSection<EndianSlice<'input, E>>,
3757            T::Offset: UnwindOffset<usize>,
3758        {
3759            EndianSlice::new(contents, E::default()).into()
3760        }
3761    }
3762
3763    fn debug_frame_le<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, LittleEndian>>> {
3764        SectionKind(PhantomData)
3765    }
3766
3767    fn debug_frame_be<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, BigEndian>>> {
3768        SectionKind(PhantomData)
3769    }
3770
3771    fn eh_frame_le<'a>() -> SectionKind<EhFrame<EndianSlice<'a, LittleEndian>>> {
3772        SectionKind(PhantomData)
3773    }
3774
3775    fn parse_fde<Section, O, F, R>(
3776        section: Section,
3777        input: &mut R,
3778        get_cie: F,
3779    ) -> Result<FrameDescriptionEntry<R>>
3780    where
3781        R: Reader,
3782        Section: UnwindSection<R, Offset = O>,
3783        O: UnwindOffset<R::Offset>,
3784        F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>,
3785    {
3786        let bases = Default::default();
3787        match parse_cfi_entry(&bases, &section, input) {
3788            Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie),
3789            Ok(_) => Err(Error::NoEntryAtGivenOffset),
3790            Err(e) => Err(e),
3791        }
3792    }
3793
3794    // Mixin methods for `Section` to help define binary test data.
3795
3796    trait CfiSectionMethods: GimliSectionMethods {
3797        fn cie<'aug, 'input, E, T>(
3798            self,
3799            _kind: SectionKind<T>,
3800            augmentation: Option<&'aug str>,
3801            cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3802        ) -> Self
3803        where
3804            E: Endianity,
3805            T: UnwindSection<EndianSlice<'input, E>>,
3806            T::Offset: UnwindOffset;
3807        fn fde<'a, 'input, E, T, L>(
3808            self,
3809            _kind: SectionKind<T>,
3810            cie_offset: L,
3811            fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3812        ) -> Self
3813        where
3814            E: Endianity,
3815            T: UnwindSection<EndianSlice<'input, E>>,
3816            T::Offset: UnwindOffset,
3817            L: ToLabelOrNum<'a, u64>;
3818    }
3819
3820    impl CfiSectionMethods for Section {
3821        fn cie<'aug, 'input, E, T>(
3822            self,
3823            _kind: SectionKind<T>,
3824            augmentation: Option<&'aug str>,
3825            cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3826        ) -> Self
3827        where
3828            E: Endianity,
3829            T: UnwindSection<EndianSlice<'input, E>>,
3830            T::Offset: UnwindOffset,
3831        {
3832            cie.offset = self.size() as _;
3833            let length = Label::new();
3834            let start = Label::new();
3835            let end = Label::new();
3836
3837            let section = match cie.format {
3838                Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff),
3839                Format::Dwarf64 => {
3840                    let section = self.D32(0xffff_ffff);
3841                    section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff)
3842                }
3843            };
3844
3845            let mut section = section.D8(cie.version);
3846
3847            if let Some(augmentation) = augmentation {
3848                section = section.append_bytes(augmentation.as_bytes());
3849            }
3850
3851            // Null terminator for augmentation string.
3852            let section = section.D8(0);
3853
3854            let section = if T::has_address_and_segment_sizes(cie.version) {
3855                section.D8(cie.address_size).D8(0)
3856            } else {
3857                section
3858            };
3859
3860            let section = section
3861                .uleb(cie.code_alignment_factor)
3862                .sleb(cie.data_alignment_factor)
3863                .uleb(cie.return_address_register.0.into())
3864                .append_bytes(cie.initial_instructions.slice())
3865                .mark(&end);
3866
3867            cie.length = (&end - &start) as usize;
3868            length.set_const(cie.length as u64);
3869
3870            section
3871        }
3872
3873        fn fde<'a, 'input, E, T, L>(
3874            self,
3875            _kind: SectionKind<T>,
3876            cie_offset: L,
3877            fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3878        ) -> Self
3879        where
3880            E: Endianity,
3881            T: UnwindSection<EndianSlice<'input, E>>,
3882            T::Offset: UnwindOffset,
3883            L: ToLabelOrNum<'a, u64>,
3884        {
3885            fde.offset = self.size() as _;
3886            let length = Label::new();
3887            let start = Label::new();
3888            let end = Label::new();
3889
3890            assert_eq!(fde.format, fde.cie.format);
3891
3892            let section = match T::cie_offset_encoding(fde.format) {
3893                CieOffsetEncoding::U32 => {
3894                    let section = self.D32(&length).mark(&start);
3895                    match cie_offset.to_labelornum() {
3896                        LabelOrNum::Label(ref l) => section.D32(l),
3897                        LabelOrNum::Num(o) => section.D32(o as u32),
3898                    }
3899                }
3900                CieOffsetEncoding::U64 => {
3901                    let section = self.D32(0xffff_ffff);
3902                    section.D64(&length).mark(&start).D64(cie_offset)
3903                }
3904            };
3905
3906            let section = match fde.cie.address_size {
3907                4 => section
3908                    .D32(fde.initial_address() as u32)
3909                    .D32(fde.len() as u32),
3910                8 => section.D64(fde.initial_address()).D64(fde.len()),
3911                x => panic!("Unsupported address size: {}", x),
3912            };
3913
3914            let section = if let Some(ref augmentation) = fde.augmentation {
3915                let cie_aug = fde
3916                    .cie
3917                    .augmentation
3918                    .expect("FDE has augmentation, but CIE doesn't");
3919
3920                if let Some(lsda) = augmentation.lsda {
3921                    // We only support writing `DW_EH_PE_absptr` here.
3922                    assert_eq!(
3923                        cie_aug
3924                            .lsda
3925                            .expect("FDE has lsda, but CIE doesn't")
3926                            .format(),
3927                        constants::DW_EH_PE_absptr
3928                    );
3929
3930                    // Augmentation data length
3931                    let section = section.uleb(u64::from(fde.cie.address_size));
3932                    match fde.cie.address_size {
3933                        4 => section.D32({
3934                            let x: u64 = lsda.pointer();
3935                            x as u32
3936                        }),
3937                        8 => section.D64({
3938                            let x: u64 = lsda.pointer();
3939                            x
3940                        }),
3941                        x => panic!("Unsupported address size: {}", x),
3942                    }
3943                } else {
3944                    // Even if we don't have any augmentation data, if there is
3945                    // an augmentation defined, we need to put the length in.
3946                    section.uleb(0)
3947                }
3948            } else {
3949                section
3950            };
3951
3952            let section = section.append_bytes(fde.instructions.slice()).mark(&end);
3953
3954            fde.length = (&end - &start) as usize;
3955            length.set_const(fde.length as u64);
3956
3957            section
3958        }
3959    }
3960
3961    trait ResultExt {
3962        fn map_eof(self, input: &[u8]) -> Self;
3963    }
3964
3965    impl<T> ResultExt for Result<T> {
3966        fn map_eof(self, input: &[u8]) -> Self {
3967            match self {
3968                Err(Error::UnexpectedEof(id)) => {
3969                    let id = ReaderOffsetId(id.0 - input.as_ptr() as u64);
3970                    Err(Error::UnexpectedEof(id))
3971                }
3972                r => r,
3973            }
3974        }
3975    }
3976
3977    fn assert_parse_cie<'input, E>(
3978        kind: SectionKind<DebugFrame<EndianSlice<'input, E>>>,
3979        section: Section,
3980        address_size: u8,
3981        expected: Result<(
3982            EndianSlice<'input, E>,
3983            CommonInformationEntry<EndianSlice<'input, E>>,
3984        )>,
3985    ) where
3986        E: Endianity,
3987    {
3988        let section = section.get_contents().unwrap();
3989        let mut debug_frame = kind.section(&section);
3990        debug_frame.set_address_size(address_size);
3991        let input = &mut EndianSlice::new(&section, E::default());
3992        let bases = Default::default();
3993        let result = CommonInformationEntry::parse(&bases, &debug_frame, input);
3994        let result = result.map(|cie| (*input, cie)).map_eof(&section);
3995        assert_eq!(result, expected);
3996    }
3997
3998    #[test]
3999    fn test_parse_cie_incomplete_length_32() {
4000        let kind = debug_frame_le();
4001        let section = Section::with_endian(kind.endian()).L16(5);
4002        assert_parse_cie(
4003            kind,
4004            section,
4005            8,
4006            Err(Error::UnexpectedEof(ReaderOffsetId(0))),
4007        );
4008    }
4009
4010    #[test]
4011    fn test_parse_cie_incomplete_length_64() {
4012        let kind = debug_frame_le();
4013        let section = Section::with_endian(kind.endian())
4014            .L32(0xffff_ffff)
4015            .L32(12345);
4016        assert_parse_cie(
4017            kind,
4018            section,
4019            8,
4020            Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4021        );
4022    }
4023
4024    #[test]
4025    fn test_parse_cie_incomplete_id_32() {
4026        let kind = debug_frame_be();
4027        let section = Section::with_endian(kind.endian())
4028            // The length is not large enough to contain the ID.
4029            .B32(3)
4030            .B32(0xffff_ffff);
4031        assert_parse_cie(
4032            kind,
4033            section,
4034            8,
4035            Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4036        );
4037    }
4038
4039    #[test]
4040    fn test_parse_cie_bad_id_32() {
4041        let kind = debug_frame_be();
4042        let section = Section::with_endian(kind.endian())
4043            // Initial length
4044            .B32(4)
4045            // Not the CIE Id.
4046            .B32(0xbad1_bad2);
4047        assert_parse_cie(kind, section, 8, Err(Error::NotCieId));
4048    }
4049
4050    #[test]
4051    fn test_parse_cie_32_bad_version() {
4052        let mut cie = CommonInformationEntry {
4053            offset: 0,
4054            length: 0,
4055            format: Format::Dwarf32,
4056            version: 99,
4057            augmentation: None,
4058            address_size: 4,
4059            code_alignment_factor: 1,
4060            data_alignment_factor: 2,
4061            return_address_register: Register(3),
4062            initial_instructions: EndianSlice::new(&[], LittleEndian),
4063        };
4064
4065        let kind = debug_frame_le();
4066        let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4067        assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99)));
4068    }
4069
4070    #[test]
4071    fn test_parse_cie_unknown_augmentation() {
4072        let length = Label::new();
4073        let start = Label::new();
4074        let end = Label::new();
4075
4076        let augmentation = "replicant";
4077        let expected_rest = [1, 2, 3];
4078
4079        let kind = debug_frame_le();
4080        let section = Section::with_endian(kind.endian())
4081            // Initial length
4082            .L32(&length)
4083            .mark(&start)
4084            // CIE Id
4085            .L32(0xffff_ffff)
4086            // Version
4087            .D8(4)
4088            // Augmentation
4089            .append_bytes(augmentation.as_bytes())
4090            // Null terminator
4091            .D8(0)
4092            // Extra augmented data that we can't understand.
4093            .L32(1)
4094            .L32(2)
4095            .L32(3)
4096            .L32(4)
4097            .L32(5)
4098            .L32(6)
4099            .mark(&end)
4100            .append_bytes(&expected_rest);
4101
4102        let expected_length = (&end - &start) as u64;
4103        length.set_const(expected_length);
4104
4105        assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation));
4106    }
4107
4108    fn test_parse_cie(format: Format, version: u8, address_size: u8) {
4109        let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4110        let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4111
4112        let mut cie = CommonInformationEntry {
4113            offset: 0,
4114            length: 0,
4115            format,
4116            version,
4117            augmentation: None,
4118            address_size,
4119            code_alignment_factor: 16,
4120            data_alignment_factor: 32,
4121            return_address_register: Register(1),
4122            initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4123        };
4124
4125        let kind = debug_frame_le();
4126        let section = Section::with_endian(kind.endian())
4127            .cie(kind, None, &mut cie)
4128            .append_bytes(&expected_rest);
4129
4130        assert_parse_cie(
4131            kind,
4132            section,
4133            address_size,
4134            Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)),
4135        );
4136    }
4137
4138    #[test]
4139    fn test_parse_cie_32_ok() {
4140        test_parse_cie(Format::Dwarf32, 1, 4);
4141        test_parse_cie(Format::Dwarf32, 1, 8);
4142        test_parse_cie(Format::Dwarf32, 4, 4);
4143        test_parse_cie(Format::Dwarf32, 4, 8);
4144    }
4145
4146    #[test]
4147    fn test_parse_cie_64_ok() {
4148        test_parse_cie(Format::Dwarf64, 1, 4);
4149        test_parse_cie(Format::Dwarf64, 1, 8);
4150        test_parse_cie(Format::Dwarf64, 4, 4);
4151        test_parse_cie(Format::Dwarf64, 4, 8);
4152    }
4153
4154    #[test]
4155    fn test_parse_cie_length_too_big() {
4156        let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect();
4157
4158        let mut cie = CommonInformationEntry {
4159            offset: 0,
4160            length: 0,
4161            format: Format::Dwarf32,
4162            version: 4,
4163            augmentation: None,
4164            address_size: 4,
4165            code_alignment_factor: 0,
4166            data_alignment_factor: 0,
4167            return_address_register: Register(3),
4168            initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4169        };
4170
4171        let kind = debug_frame_le();
4172        let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4173
4174        let mut contents = section.get_contents().unwrap();
4175
4176        // Overwrite the length to be too big.
4177        contents[0] = 0;
4178        contents[1] = 0;
4179        contents[2] = 0;
4180        contents[3] = 255;
4181
4182        let debug_frame = DebugFrame::new(&contents, LittleEndian);
4183        let bases = Default::default();
4184        assert_eq!(
4185            CommonInformationEntry::parse(
4186                &bases,
4187                &debug_frame,
4188                &mut EndianSlice::new(&contents, LittleEndian)
4189            )
4190            .map_eof(&contents),
4191            Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4192        );
4193    }
4194
4195    #[test]
4196    fn test_parse_fde_incomplete_length_32() {
4197        let kind = debug_frame_le();
4198        let section = Section::with_endian(kind.endian()).L16(5);
4199        let section = section.get_contents().unwrap();
4200        let debug_frame = kind.section(&section);
4201        let rest = &mut EndianSlice::new(&section, LittleEndian);
4202        assert_eq!(
4203            parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
4204            Err(Error::UnexpectedEof(ReaderOffsetId(0)))
4205        );
4206    }
4207
4208    #[test]
4209    fn test_parse_fde_incomplete_length_64() {
4210        let kind = debug_frame_le();
4211        let section = Section::with_endian(kind.endian())
4212            .L32(0xffff_ffff)
4213            .L32(12345);
4214        let section = section.get_contents().unwrap();
4215        let debug_frame = kind.section(&section);
4216        let rest = &mut EndianSlice::new(&section, LittleEndian);
4217        assert_eq!(
4218            parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
4219            Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4220        );
4221    }
4222
4223    #[test]
4224    fn test_parse_fde_incomplete_cie_pointer_32() {
4225        let kind = debug_frame_be();
4226        let section = Section::with_endian(kind.endian())
4227            // The length is not large enough to contain the CIE pointer.
4228            .B32(3)
4229            .B32(1994);
4230        let section = section.get_contents().unwrap();
4231        let debug_frame = kind.section(&section);
4232        let rest = &mut EndianSlice::new(&section, BigEndian);
4233        assert_eq!(
4234            parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(&section),
4235            Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4236        );
4237    }
4238
4239    #[test]
4240    fn test_parse_fde_32_ok() {
4241        let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4242        let cie_offset = 0xbad0_bad1;
4243        let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4244
4245        let cie = CommonInformationEntry {
4246            offset: 0,
4247            length: 100,
4248            format: Format::Dwarf32,
4249            version: 4,
4250            augmentation: None,
4251            // DWARF32 with a 64 bit address size! Holy moly!
4252            address_size: 8,
4253            code_alignment_factor: 3,
4254            data_alignment_factor: 2,
4255            return_address_register: Register(1),
4256            initial_instructions: EndianSlice::new(&[], LittleEndian),
4257        };
4258
4259        let mut fde = FrameDescriptionEntry {
4260            offset: 0,
4261            length: 0,
4262            format: Format::Dwarf32,
4263            cie: cie.clone(),
4264            initial_address: 0xfeed_beef,
4265            address_range: 39,
4266            augmentation: None,
4267            instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4268        };
4269
4270        let kind = debug_frame_le();
4271        let section = Section::with_endian(kind.endian())
4272            .fde(kind, cie_offset, &mut fde)
4273            .append_bytes(&expected_rest);
4274
4275        let section = section.get_contents().unwrap();
4276        let debug_frame = kind.section(&section);
4277        let rest = &mut EndianSlice::new(&section, LittleEndian);
4278
4279        let get_cie = |_: &_, _: &_, offset| {
4280            assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4281            Ok(cie.clone())
4282        };
4283
4284        assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4285        assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4286    }
4287
4288    #[test]
4289    fn test_parse_fde_64_ok() {
4290        let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4291        let cie_offset = 0xbad0_bad1;
4292        let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4293
4294        let cie = CommonInformationEntry {
4295            offset: 0,
4296            length: 100,
4297            format: Format::Dwarf64,
4298            version: 4,
4299            augmentation: None,
4300            address_size: 8,
4301            code_alignment_factor: 3,
4302            data_alignment_factor: 2,
4303            return_address_register: Register(1),
4304            initial_instructions: EndianSlice::new(&[], LittleEndian),
4305        };
4306
4307        let mut fde = FrameDescriptionEntry {
4308            offset: 0,
4309            length: 0,
4310            format: Format::Dwarf64,
4311            cie: cie.clone(),
4312            initial_address: 0xfeed_beef,
4313            address_range: 999,
4314            augmentation: None,
4315            instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4316        };
4317
4318        let kind = debug_frame_le();
4319        let section = Section::with_endian(kind.endian())
4320            .fde(kind, cie_offset, &mut fde)
4321            .append_bytes(&expected_rest);
4322
4323        let section = section.get_contents().unwrap();
4324        let debug_frame = kind.section(&section);
4325        let rest = &mut EndianSlice::new(&section, LittleEndian);
4326
4327        let get_cie = |_: &_, _: &_, offset| {
4328            assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4329            Ok(cie.clone())
4330        };
4331
4332        assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4333        assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4334    }
4335
4336    #[test]
4337    fn test_parse_cfi_entry_on_cie_32_ok() {
4338        let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4339        let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4340
4341        let mut cie = CommonInformationEntry {
4342            offset: 0,
4343            length: 0,
4344            format: Format::Dwarf32,
4345            version: 4,
4346            augmentation: None,
4347            address_size: 4,
4348            code_alignment_factor: 16,
4349            data_alignment_factor: 32,
4350            return_address_register: Register(1),
4351            initial_instructions: EndianSlice::new(&expected_instrs, BigEndian),
4352        };
4353
4354        let kind = debug_frame_be();
4355        let section = Section::with_endian(kind.endian())
4356            .cie(kind, None, &mut cie)
4357            .append_bytes(&expected_rest);
4358        let section = section.get_contents().unwrap();
4359        let debug_frame = kind.section(&section);
4360        let rest = &mut EndianSlice::new(&section, BigEndian);
4361
4362        let bases = Default::default();
4363        assert_eq!(
4364            parse_cfi_entry(&bases, &debug_frame, rest),
4365            Ok(Some(CieOrFde::Cie(cie)))
4366        );
4367        assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4368    }
4369
4370    #[test]
4371    fn test_parse_cfi_entry_on_fde_32_ok() {
4372        let cie_offset = 0x1234_5678;
4373        let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4374        let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4375
4376        let cie = CommonInformationEntry {
4377            offset: 0,
4378            length: 0,
4379            format: Format::Dwarf32,
4380            version: 4,
4381            augmentation: None,
4382            address_size: 4,
4383            code_alignment_factor: 16,
4384            data_alignment_factor: 32,
4385            return_address_register: Register(1),
4386            initial_instructions: EndianSlice::new(&[], BigEndian),
4387        };
4388
4389        let mut fde = FrameDescriptionEntry {
4390            offset: 0,
4391            length: 0,
4392            format: Format::Dwarf32,
4393            cie: cie.clone(),
4394            initial_address: 0xfeed_beef,
4395            address_range: 39,
4396            augmentation: None,
4397            instructions: EndianSlice::new(&expected_instrs, BigEndian),
4398        };
4399
4400        let kind = debug_frame_be();
4401        let section = Section::with_endian(kind.endian())
4402            .fde(kind, cie_offset, &mut fde)
4403            .append_bytes(&expected_rest);
4404
4405        let section = section.get_contents().unwrap();
4406        let debug_frame = kind.section(&section);
4407        let rest = &mut EndianSlice::new(&section, BigEndian);
4408
4409        let bases = Default::default();
4410        match parse_cfi_entry(&bases, &debug_frame, rest) {
4411            Ok(Some(CieOrFde::Fde(partial))) => {
4412                assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4413
4414                assert_eq!(partial.length, fde.length);
4415                assert_eq!(partial.format, fde.format);
4416                assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize));
4417
4418                let get_cie = |_: &_, _: &_, offset| {
4419                    assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4420                    Ok(cie.clone())
4421                };
4422
4423                assert_eq!(partial.parse(get_cie), Ok(fde));
4424            }
4425            otherwise => panic!("Unexpected result: {:#?}", otherwise),
4426        }
4427    }
4428
4429    #[test]
4430    fn test_cfi_entries_iter() {
4431        let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4432
4433        let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
4434
4435        let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect();
4436
4437        let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
4438
4439        let mut cie1 = CommonInformationEntry {
4440            offset: 0,
4441            length: 0,
4442            format: Format::Dwarf32,
4443            version: 4,
4444            augmentation: None,
4445            address_size: 4,
4446            code_alignment_factor: 1,
4447            data_alignment_factor: 2,
4448            return_address_register: Register(3),
4449            initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian),
4450        };
4451
4452        let mut cie2 = CommonInformationEntry {
4453            offset: 0,
4454            length: 0,
4455            format: Format::Dwarf32,
4456            version: 4,
4457            augmentation: None,
4458            address_size: 4,
4459            code_alignment_factor: 3,
4460            data_alignment_factor: 2,
4461            return_address_register: Register(1),
4462            initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian),
4463        };
4464
4465        let cie1_location = Label::new();
4466        let cie2_location = Label::new();
4467
4468        // Write the CIEs first so that their length gets set before we clone
4469        // them into the FDEs and our equality assertions down the line end up
4470        // with all the CIEs always having he correct length.
4471        let kind = debug_frame_be();
4472        let section = Section::with_endian(kind.endian())
4473            .mark(&cie1_location)
4474            .cie(kind, None, &mut cie1)
4475            .mark(&cie2_location)
4476            .cie(kind, None, &mut cie2);
4477
4478        let mut fde1 = FrameDescriptionEntry {
4479            offset: 0,
4480            length: 0,
4481            format: Format::Dwarf32,
4482            cie: cie1.clone(),
4483            initial_address: 0xfeed_beef,
4484            address_range: 39,
4485            augmentation: None,
4486            instructions: EndianSlice::new(&expected_instrs3, BigEndian),
4487        };
4488
4489        let mut fde2 = FrameDescriptionEntry {
4490            offset: 0,
4491            length: 0,
4492            format: Format::Dwarf32,
4493            cie: cie2.clone(),
4494            initial_address: 0xfeed_face,
4495            address_range: 9000,
4496            augmentation: None,
4497            instructions: EndianSlice::new(&expected_instrs4, BigEndian),
4498        };
4499
4500        let section =
4501            section
4502                .fde(kind, &cie1_location, &mut fde1)
4503                .fde(kind, &cie2_location, &mut fde2);
4504
4505        section.start().set_const(0);
4506
4507        let cie1_offset = cie1_location.value().unwrap() as usize;
4508        let cie2_offset = cie2_location.value().unwrap() as usize;
4509
4510        let contents = section.get_contents().unwrap();
4511        let debug_frame = kind.section(&contents);
4512
4513        let bases = Default::default();
4514        let mut entries = debug_frame.entries(&bases);
4515
4516        assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone()))));
4517        assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone()))));
4518
4519        match entries.next() {
4520            Ok(Some(CieOrFde::Fde(partial))) => {
4521                assert_eq!(partial.length, fde1.length);
4522                assert_eq!(partial.format, fde1.format);
4523                assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset));
4524
4525                let get_cie = |_: &_, _: &_, offset| {
4526                    assert_eq!(offset, DebugFrameOffset(cie1_offset));
4527                    Ok(cie1.clone())
4528                };
4529                assert_eq!(partial.parse(get_cie), Ok(fde1));
4530            }
4531            otherwise => panic!("Unexpected result: {:#?}", otherwise),
4532        }
4533
4534        match entries.next() {
4535            Ok(Some(CieOrFde::Fde(partial))) => {
4536                assert_eq!(partial.length, fde2.length);
4537                assert_eq!(partial.format, fde2.format);
4538                assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset));
4539
4540                let get_cie = |_: &_, _: &_, offset| {
4541                    assert_eq!(offset, DebugFrameOffset(cie2_offset));
4542                    Ok(cie2.clone())
4543                };
4544                assert_eq!(partial.parse(get_cie), Ok(fde2));
4545            }
4546            otherwise => panic!("Unexpected result: {:#?}", otherwise),
4547        }
4548
4549        assert_eq!(entries.next(), Ok(None));
4550    }
4551
4552    #[test]
4553    fn test_parse_cie_from_offset() {
4554        let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4555        let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect();
4556
4557        let mut cie = CommonInformationEntry {
4558            offset: 0,
4559            length: 0,
4560            format: Format::Dwarf64,
4561            version: 4,
4562            augmentation: None,
4563            address_size: 4,
4564            code_alignment_factor: 4,
4565            data_alignment_factor: 8,
4566            return_address_register: Register(12),
4567            initial_instructions: EndianSlice::new(&instrs, LittleEndian),
4568        };
4569
4570        let cie_location = Label::new();
4571
4572        let kind = debug_frame_le();
4573        let section = Section::with_endian(kind.endian())
4574            .append_bytes(&filler)
4575            .mark(&cie_location)
4576            .cie(kind, None, &mut cie)
4577            .append_bytes(&filler);
4578
4579        section.start().set_const(0);
4580
4581        let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize);
4582
4583        let contents = section.get_contents().unwrap();
4584        let debug_frame = kind.section(&contents);
4585        let bases = Default::default();
4586
4587        assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie));
4588    }
4589
4590    fn parse_cfi_instruction<R: Reader + Default>(
4591        input: &mut R,
4592        address_size: u8,
4593    ) -> Result<CallFrameInstruction<R::Offset>> {
4594        let section = input.clone();
4595        let parameters = &PointerEncodingParameters {
4596            bases: &SectionBaseAddresses::default(),
4597            func_base: None,
4598            address_size,
4599            section: &section,
4600        };
4601        CallFrameInstruction::parse(input, None, parameters, Vendor::Default)
4602    }
4603
4604    #[test]
4605    fn test_parse_cfi_instruction_advance_loc() {
4606        let expected_rest = [1, 2, 3, 4];
4607        let expected_delta = 42;
4608        let section = Section::with_endian(Endian::Little)
4609            .D8(constants::DW_CFA_advance_loc.0 | expected_delta)
4610            .append_bytes(&expected_rest);
4611        let contents = section.get_contents().unwrap();
4612        let input = &mut EndianSlice::new(&contents, LittleEndian);
4613        assert_eq!(
4614            parse_cfi_instruction(input, 8),
4615            Ok(CallFrameInstruction::AdvanceLoc {
4616                delta: u32::from(expected_delta),
4617            })
4618        );
4619        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4620    }
4621
4622    #[test]
4623    fn test_parse_cfi_instruction_offset() {
4624        let expected_rest = [1, 2, 3, 4];
4625        let expected_reg = 3;
4626        let expected_offset = 1997;
4627        let section = Section::with_endian(Endian::Little)
4628            .D8(constants::DW_CFA_offset.0 | expected_reg)
4629            .uleb(expected_offset)
4630            .append_bytes(&expected_rest);
4631        let contents = section.get_contents().unwrap();
4632        let input = &mut EndianSlice::new(&contents, LittleEndian);
4633        assert_eq!(
4634            parse_cfi_instruction(input, 8),
4635            Ok(CallFrameInstruction::Offset {
4636                register: Register(expected_reg.into()),
4637                factored_offset: expected_offset,
4638            })
4639        );
4640        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4641    }
4642
4643    #[test]
4644    fn test_parse_cfi_instruction_restore() {
4645        let expected_rest = [1, 2, 3, 4];
4646        let expected_reg = 3;
4647        let section = Section::with_endian(Endian::Little)
4648            .D8(constants::DW_CFA_restore.0 | expected_reg)
4649            .append_bytes(&expected_rest);
4650        let contents = section.get_contents().unwrap();
4651        let input = &mut EndianSlice::new(&contents, LittleEndian);
4652        assert_eq!(
4653            parse_cfi_instruction(input, 8),
4654            Ok(CallFrameInstruction::Restore {
4655                register: Register(expected_reg.into()),
4656            })
4657        );
4658        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4659    }
4660
4661    #[test]
4662    fn test_parse_cfi_instruction_nop() {
4663        let expected_rest = [1, 2, 3, 4];
4664        let section = Section::with_endian(Endian::Little)
4665            .D8(constants::DW_CFA_nop.0)
4666            .append_bytes(&expected_rest);
4667        let contents = section.get_contents().unwrap();
4668        let input = &mut EndianSlice::new(&contents, LittleEndian);
4669        assert_eq!(
4670            parse_cfi_instruction(input, 8),
4671            Ok(CallFrameInstruction::Nop)
4672        );
4673        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4674    }
4675
4676    #[test]
4677    fn test_parse_cfi_instruction_set_loc() {
4678        let expected_rest = [1, 2, 3, 4];
4679        let expected_addr = 0xdead_beef;
4680        let section = Section::with_endian(Endian::Little)
4681            .D8(constants::DW_CFA_set_loc.0)
4682            .L64(expected_addr)
4683            .append_bytes(&expected_rest);
4684        let contents = section.get_contents().unwrap();
4685        let input = &mut EndianSlice::new(&contents, LittleEndian);
4686        assert_eq!(
4687            parse_cfi_instruction(input, 8),
4688            Ok(CallFrameInstruction::SetLoc {
4689                address: expected_addr,
4690            })
4691        );
4692        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4693    }
4694
4695    #[test]
4696    fn test_parse_cfi_instruction_set_loc_encoding() {
4697        let text_base = 0xfeed_face;
4698        let addr_offset = 0xbeef;
4699        let expected_addr = text_base + addr_offset;
4700        let expected_rest = [1, 2, 3, 4];
4701        let section = Section::with_endian(Endian::Little)
4702            .D8(constants::DW_CFA_set_loc.0)
4703            .L64(addr_offset)
4704            .append_bytes(&expected_rest);
4705        let contents = section.get_contents().unwrap();
4706        let input = &mut EndianSlice::new(&contents, LittleEndian);
4707        let parameters = &PointerEncodingParameters {
4708            bases: &BaseAddresses::default().set_text(text_base).eh_frame,
4709            func_base: None,
4710            address_size: 8,
4711            section: &EndianSlice::new(&[], LittleEndian),
4712        };
4713        assert_eq!(
4714            CallFrameInstruction::parse(
4715                input,
4716                Some(constants::DW_EH_PE_textrel),
4717                parameters,
4718                Vendor::Default
4719            ),
4720            Ok(CallFrameInstruction::SetLoc {
4721                address: expected_addr,
4722            })
4723        );
4724        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4725    }
4726
4727    #[test]
4728    fn test_parse_cfi_instruction_advance_loc1() {
4729        let expected_rest = [1, 2, 3, 4];
4730        let expected_delta = 8;
4731        let section = Section::with_endian(Endian::Little)
4732            .D8(constants::DW_CFA_advance_loc1.0)
4733            .D8(expected_delta)
4734            .append_bytes(&expected_rest);
4735        let contents = section.get_contents().unwrap();
4736        let input = &mut EndianSlice::new(&contents, LittleEndian);
4737        assert_eq!(
4738            parse_cfi_instruction(input, 8),
4739            Ok(CallFrameInstruction::AdvanceLoc {
4740                delta: u32::from(expected_delta),
4741            })
4742        );
4743        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4744    }
4745
4746    #[test]
4747    fn test_parse_cfi_instruction_advance_loc2() {
4748        let expected_rest = [1, 2, 3, 4];
4749        let expected_delta = 500;
4750        let section = Section::with_endian(Endian::Little)
4751            .D8(constants::DW_CFA_advance_loc2.0)
4752            .L16(expected_delta)
4753            .append_bytes(&expected_rest);
4754        let contents = section.get_contents().unwrap();
4755        let input = &mut EndianSlice::new(&contents, LittleEndian);
4756        assert_eq!(
4757            parse_cfi_instruction(input, 8),
4758            Ok(CallFrameInstruction::AdvanceLoc {
4759                delta: u32::from(expected_delta),
4760            })
4761        );
4762        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4763    }
4764
4765    #[test]
4766    fn test_parse_cfi_instruction_advance_loc4() {
4767        let expected_rest = [1, 2, 3, 4];
4768        let expected_delta = 1 << 20;
4769        let section = Section::with_endian(Endian::Little)
4770            .D8(constants::DW_CFA_advance_loc4.0)
4771            .L32(expected_delta)
4772            .append_bytes(&expected_rest);
4773        let contents = section.get_contents().unwrap();
4774        let input = &mut EndianSlice::new(&contents, LittleEndian);
4775        assert_eq!(
4776            parse_cfi_instruction(input, 8),
4777            Ok(CallFrameInstruction::AdvanceLoc {
4778                delta: expected_delta,
4779            })
4780        );
4781        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4782    }
4783
4784    #[test]
4785    fn test_parse_cfi_instruction_offset_extended() {
4786        let expected_rest = [1, 2, 3, 4];
4787        let expected_reg = 7;
4788        let expected_offset = 33;
4789        let section = Section::with_endian(Endian::Little)
4790            .D8(constants::DW_CFA_offset_extended.0)
4791            .uleb(expected_reg.into())
4792            .uleb(expected_offset)
4793            .append_bytes(&expected_rest);
4794        let contents = section.get_contents().unwrap();
4795        let input = &mut EndianSlice::new(&contents, LittleEndian);
4796        assert_eq!(
4797            parse_cfi_instruction(input, 8),
4798            Ok(CallFrameInstruction::Offset {
4799                register: Register(expected_reg),
4800                factored_offset: expected_offset,
4801            })
4802        );
4803        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4804    }
4805
4806    #[test]
4807    fn test_parse_cfi_instruction_restore_extended() {
4808        let expected_rest = [1, 2, 3, 4];
4809        let expected_reg = 7;
4810        let section = Section::with_endian(Endian::Little)
4811            .D8(constants::DW_CFA_restore_extended.0)
4812            .uleb(expected_reg.into())
4813            .append_bytes(&expected_rest);
4814        let contents = section.get_contents().unwrap();
4815        let input = &mut EndianSlice::new(&contents, LittleEndian);
4816        assert_eq!(
4817            parse_cfi_instruction(input, 8),
4818            Ok(CallFrameInstruction::Restore {
4819                register: Register(expected_reg),
4820            })
4821        );
4822        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4823    }
4824
4825    #[test]
4826    fn test_parse_cfi_instruction_undefined() {
4827        let expected_rest = [1, 2, 3, 4];
4828        let expected_reg = 7;
4829        let section = Section::with_endian(Endian::Little)
4830            .D8(constants::DW_CFA_undefined.0)
4831            .uleb(expected_reg.into())
4832            .append_bytes(&expected_rest);
4833        let contents = section.get_contents().unwrap();
4834        let input = &mut EndianSlice::new(&contents, LittleEndian);
4835        assert_eq!(
4836            parse_cfi_instruction(input, 8),
4837            Ok(CallFrameInstruction::Undefined {
4838                register: Register(expected_reg),
4839            })
4840        );
4841        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4842    }
4843
4844    #[test]
4845    fn test_parse_cfi_instruction_same_value() {
4846        let expected_rest = [1, 2, 3, 4];
4847        let expected_reg = 7;
4848        let section = Section::with_endian(Endian::Little)
4849            .D8(constants::DW_CFA_same_value.0)
4850            .uleb(expected_reg.into())
4851            .append_bytes(&expected_rest);
4852        let contents = section.get_contents().unwrap();
4853        let input = &mut EndianSlice::new(&contents, LittleEndian);
4854        assert_eq!(
4855            parse_cfi_instruction(input, 8),
4856            Ok(CallFrameInstruction::SameValue {
4857                register: Register(expected_reg),
4858            })
4859        );
4860        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4861    }
4862
4863    #[test]
4864    fn test_parse_cfi_instruction_register() {
4865        let expected_rest = [1, 2, 3, 4];
4866        let expected_dest_reg = 7;
4867        let expected_src_reg = 8;
4868        let section = Section::with_endian(Endian::Little)
4869            .D8(constants::DW_CFA_register.0)
4870            .uleb(expected_dest_reg.into())
4871            .uleb(expected_src_reg.into())
4872            .append_bytes(&expected_rest);
4873        let contents = section.get_contents().unwrap();
4874        let input = &mut EndianSlice::new(&contents, LittleEndian);
4875        assert_eq!(
4876            parse_cfi_instruction(input, 8),
4877            Ok(CallFrameInstruction::Register {
4878                dest_register: Register(expected_dest_reg),
4879                src_register: Register(expected_src_reg),
4880            })
4881        );
4882        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4883    }
4884
4885    #[test]
4886    fn test_parse_cfi_instruction_remember_state() {
4887        let expected_rest = [1, 2, 3, 4];
4888        let section = Section::with_endian(Endian::Little)
4889            .D8(constants::DW_CFA_remember_state.0)
4890            .append_bytes(&expected_rest);
4891        let contents = section.get_contents().unwrap();
4892        let input = &mut EndianSlice::new(&contents, LittleEndian);
4893        assert_eq!(
4894            parse_cfi_instruction(input, 8),
4895            Ok(CallFrameInstruction::RememberState)
4896        );
4897        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4898    }
4899
4900    #[test]
4901    fn test_parse_cfi_instruction_restore_state() {
4902        let expected_rest = [1, 2, 3, 4];
4903        let section = Section::with_endian(Endian::Little)
4904            .D8(constants::DW_CFA_restore_state.0)
4905            .append_bytes(&expected_rest);
4906        let contents = section.get_contents().unwrap();
4907        let input = &mut EndianSlice::new(&contents, LittleEndian);
4908        assert_eq!(
4909            parse_cfi_instruction(input, 8),
4910            Ok(CallFrameInstruction::RestoreState)
4911        );
4912        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4913    }
4914
4915    #[test]
4916    fn test_parse_cfi_instruction_def_cfa() {
4917        let expected_rest = [1, 2, 3, 4];
4918        let expected_reg = 2;
4919        let expected_offset = 0;
4920        let section = Section::with_endian(Endian::Little)
4921            .D8(constants::DW_CFA_def_cfa.0)
4922            .uleb(expected_reg.into())
4923            .uleb(expected_offset)
4924            .append_bytes(&expected_rest);
4925        let contents = section.get_contents().unwrap();
4926        let input = &mut EndianSlice::new(&contents, LittleEndian);
4927        assert_eq!(
4928            parse_cfi_instruction(input, 8),
4929            Ok(CallFrameInstruction::DefCfa {
4930                register: Register(expected_reg),
4931                offset: expected_offset,
4932            })
4933        );
4934        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4935    }
4936
4937    #[test]
4938    fn test_parse_cfi_instruction_def_cfa_register() {
4939        let expected_rest = [1, 2, 3, 4];
4940        let expected_reg = 2;
4941        let section = Section::with_endian(Endian::Little)
4942            .D8(constants::DW_CFA_def_cfa_register.0)
4943            .uleb(expected_reg.into())
4944            .append_bytes(&expected_rest);
4945        let contents = section.get_contents().unwrap();
4946        let input = &mut EndianSlice::new(&contents, LittleEndian);
4947        assert_eq!(
4948            parse_cfi_instruction(input, 8),
4949            Ok(CallFrameInstruction::DefCfaRegister {
4950                register: Register(expected_reg),
4951            })
4952        );
4953        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4954    }
4955
4956    #[test]
4957    fn test_parse_cfi_instruction_def_cfa_offset() {
4958        let expected_rest = [1, 2, 3, 4];
4959        let expected_offset = 23;
4960        let section = Section::with_endian(Endian::Little)
4961            .D8(constants::DW_CFA_def_cfa_offset.0)
4962            .uleb(expected_offset)
4963            .append_bytes(&expected_rest);
4964        let contents = section.get_contents().unwrap();
4965        let input = &mut EndianSlice::new(&contents, LittleEndian);
4966        assert_eq!(
4967            parse_cfi_instruction(input, 8),
4968            Ok(CallFrameInstruction::DefCfaOffset {
4969                offset: expected_offset,
4970            })
4971        );
4972        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4973    }
4974
4975    #[test]
4976    fn test_parse_cfi_instruction_def_cfa_expression() {
4977        let expected_rest = [1, 2, 3, 4];
4978        let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
4979
4980        let length = Label::new();
4981        let start = Label::new();
4982        let end = Label::new();
4983
4984        let section = Section::with_endian(Endian::Little)
4985            .D8(constants::DW_CFA_def_cfa_expression.0)
4986            .D8(&length)
4987            .mark(&start)
4988            .append_bytes(&expected_expr)
4989            .mark(&end)
4990            .append_bytes(&expected_rest);
4991
4992        length.set_const((&end - &start) as u64);
4993        let expected_expression = UnwindExpression {
4994            offset: (&start - &section.start()) as usize,
4995            length: (&end - &start) as usize,
4996        };
4997        let contents = section.get_contents().unwrap();
4998        let input = &mut EndianSlice::new(&contents, LittleEndian);
4999
5000        assert_eq!(
5001            parse_cfi_instruction(input, 8),
5002            Ok(CallFrameInstruction::DefCfaExpression {
5003                expression: expected_expression,
5004            })
5005        );
5006        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5007    }
5008
5009    #[test]
5010    fn test_parse_cfi_instruction_expression() {
5011        let expected_rest = [1, 2, 3, 4];
5012        let expected_reg = 99;
5013        let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
5014
5015        let length = Label::new();
5016        let start = Label::new();
5017        let end = Label::new();
5018
5019        let section = Section::with_endian(Endian::Little)
5020            .D8(constants::DW_CFA_expression.0)
5021            .uleb(expected_reg.into())
5022            .D8(&length)
5023            .mark(&start)
5024            .append_bytes(&expected_expr)
5025            .mark(&end)
5026            .append_bytes(&expected_rest);
5027
5028        length.set_const((&end - &start) as u64);
5029        let expected_expression = UnwindExpression {
5030            offset: (&start - &section.start()) as usize,
5031            length: (&end - &start) as usize,
5032        };
5033        let contents = section.get_contents().unwrap();
5034        let input = &mut EndianSlice::new(&contents, LittleEndian);
5035
5036        assert_eq!(
5037            parse_cfi_instruction(input, 8),
5038            Ok(CallFrameInstruction::Expression {
5039                register: Register(expected_reg),
5040                expression: expected_expression,
5041            })
5042        );
5043        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5044    }
5045
5046    #[test]
5047    fn test_parse_cfi_instruction_offset_extended_sf() {
5048        let expected_rest = [1, 2, 3, 4];
5049        let expected_reg = 7;
5050        let expected_offset = -33;
5051        let section = Section::with_endian(Endian::Little)
5052            .D8(constants::DW_CFA_offset_extended_sf.0)
5053            .uleb(expected_reg.into())
5054            .sleb(expected_offset)
5055            .append_bytes(&expected_rest);
5056        let contents = section.get_contents().unwrap();
5057        let input = &mut EndianSlice::new(&contents, LittleEndian);
5058        assert_eq!(
5059            parse_cfi_instruction(input, 8),
5060            Ok(CallFrameInstruction::OffsetExtendedSf {
5061                register: Register(expected_reg),
5062                factored_offset: expected_offset,
5063            })
5064        );
5065        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5066    }
5067
5068    #[test]
5069    fn test_parse_cfi_instruction_def_cfa_sf() {
5070        let expected_rest = [1, 2, 3, 4];
5071        let expected_reg = 2;
5072        let expected_offset = -9999;
5073        let section = Section::with_endian(Endian::Little)
5074            .D8(constants::DW_CFA_def_cfa_sf.0)
5075            .uleb(expected_reg.into())
5076            .sleb(expected_offset)
5077            .append_bytes(&expected_rest);
5078        let contents = section.get_contents().unwrap();
5079        let input = &mut EndianSlice::new(&contents, LittleEndian);
5080        assert_eq!(
5081            parse_cfi_instruction(input, 8),
5082            Ok(CallFrameInstruction::DefCfaSf {
5083                register: Register(expected_reg),
5084                factored_offset: expected_offset,
5085            })
5086        );
5087        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5088    }
5089
5090    #[test]
5091    fn test_parse_cfi_instruction_def_cfa_offset_sf() {
5092        let expected_rest = [1, 2, 3, 4];
5093        let expected_offset = -123;
5094        let section = Section::with_endian(Endian::Little)
5095            .D8(constants::DW_CFA_def_cfa_offset_sf.0)
5096            .sleb(expected_offset)
5097            .append_bytes(&expected_rest);
5098        let contents = section.get_contents().unwrap();
5099        let input = &mut EndianSlice::new(&contents, LittleEndian);
5100        assert_eq!(
5101            parse_cfi_instruction(input, 8),
5102            Ok(CallFrameInstruction::DefCfaOffsetSf {
5103                factored_offset: expected_offset,
5104            })
5105        );
5106        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5107    }
5108
5109    #[test]
5110    fn test_parse_cfi_instruction_val_offset() {
5111        let expected_rest = [1, 2, 3, 4];
5112        let expected_reg = 50;
5113        let expected_offset = 23;
5114        let section = Section::with_endian(Endian::Little)
5115            .D8(constants::DW_CFA_val_offset.0)
5116            .uleb(expected_reg.into())
5117            .uleb(expected_offset)
5118            .append_bytes(&expected_rest);
5119        let contents = section.get_contents().unwrap();
5120        let input = &mut EndianSlice::new(&contents, LittleEndian);
5121        assert_eq!(
5122            parse_cfi_instruction(input, 8),
5123            Ok(CallFrameInstruction::ValOffset {
5124                register: Register(expected_reg),
5125                factored_offset: expected_offset,
5126            })
5127        );
5128        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5129    }
5130
5131    #[test]
5132    fn test_parse_cfi_instruction_val_offset_sf() {
5133        let expected_rest = [1, 2, 3, 4];
5134        let expected_reg = 50;
5135        let expected_offset = -23;
5136        let section = Section::with_endian(Endian::Little)
5137            .D8(constants::DW_CFA_val_offset_sf.0)
5138            .uleb(expected_reg.into())
5139            .sleb(expected_offset)
5140            .append_bytes(&expected_rest);
5141        let contents = section.get_contents().unwrap();
5142        let input = &mut EndianSlice::new(&contents, LittleEndian);
5143        assert_eq!(
5144            parse_cfi_instruction(input, 8),
5145            Ok(CallFrameInstruction::ValOffsetSf {
5146                register: Register(expected_reg),
5147                factored_offset: expected_offset,
5148            })
5149        );
5150        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5151    }
5152
5153    #[test]
5154    fn test_parse_cfi_instruction_val_expression() {
5155        let expected_rest = [1, 2, 3, 4];
5156        let expected_reg = 50;
5157        let expected_expr = [2, 2, 1, 1, 5, 5];
5158
5159        let length = Label::new();
5160        let start = Label::new();
5161        let end = Label::new();
5162
5163        let section = Section::with_endian(Endian::Little)
5164            .D8(constants::DW_CFA_val_expression.0)
5165            .uleb(expected_reg.into())
5166            .D8(&length)
5167            .mark(&start)
5168            .append_bytes(&expected_expr)
5169            .mark(&end)
5170            .append_bytes(&expected_rest);
5171
5172        length.set_const((&end - &start) as u64);
5173        let expected_expression = UnwindExpression {
5174            offset: (&start - &section.start()) as usize,
5175            length: (&end - &start) as usize,
5176        };
5177        let contents = section.get_contents().unwrap();
5178        let input = &mut EndianSlice::new(&contents, LittleEndian);
5179
5180        assert_eq!(
5181            parse_cfi_instruction(input, 8),
5182            Ok(CallFrameInstruction::ValExpression {
5183                register: Register(expected_reg),
5184                expression: expected_expression,
5185            })
5186        );
5187        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5188    }
5189
5190    #[test]
5191    fn test_parse_cfi_instruction_negate_ra_state() {
5192        let expected_rest = [1, 2, 3, 4];
5193        let section = Section::with_endian(Endian::Little)
5194            .D8(constants::DW_CFA_AARCH64_negate_ra_state.0)
5195            .append_bytes(&expected_rest);
5196        let contents = section.get_contents().unwrap();
5197        let input = &mut EndianSlice::new(&contents, LittleEndian);
5198        let parameters = &PointerEncodingParameters {
5199            bases: &SectionBaseAddresses::default(),
5200            func_base: None,
5201            address_size: 8,
5202            section: &EndianSlice::default(),
5203        };
5204        assert_eq!(
5205            CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64),
5206            Ok(CallFrameInstruction::NegateRaState)
5207        );
5208        assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5209    }
5210
5211    #[test]
5212    fn test_parse_cfi_instruction_unknown_instruction() {
5213        let expected_rest = [1, 2, 3, 4];
5214        let unknown_instr = constants::DwCfa(0b0011_1111);
5215        let section = Section::with_endian(Endian::Little)
5216            .D8(unknown_instr.0)
5217            .append_bytes(&expected_rest);
5218        let contents = section.get_contents().unwrap();
5219        let input = &mut EndianSlice::new(&contents, LittleEndian);
5220        assert_eq!(
5221            parse_cfi_instruction(input, 8),
5222            Err(Error::UnknownCallFrameInstruction(unknown_instr))
5223        );
5224    }
5225
5226    #[test]
5227    fn test_call_frame_instruction_iter_ok() {
5228        let expected_reg = 50;
5229        let expected_expr = [2, 2, 1, 1, 5, 5];
5230        let expected_delta = 230;
5231
5232        let length = Label::new();
5233        let start = Label::new();
5234        let end = Label::new();
5235
5236        let section = Section::with_endian(Endian::Big)
5237            .D8(constants::DW_CFA_val_expression.0)
5238            .uleb(expected_reg.into())
5239            .D8(&length)
5240            .mark(&start)
5241            .append_bytes(&expected_expr)
5242            .mark(&end)
5243            .D8(constants::DW_CFA_advance_loc1.0)
5244            .D8(expected_delta);
5245
5246        length.set_const((&end - &start) as u64);
5247        let expected_expression = UnwindExpression {
5248            offset: (&start - &section.start()) as usize,
5249            length: (&end - &start) as usize,
5250        };
5251        let contents = section.get_contents().unwrap();
5252        let input = EndianSlice::new(&contents, BigEndian);
5253        let parameters = PointerEncodingParameters {
5254            bases: &SectionBaseAddresses::default(),
5255            func_base: None,
5256            address_size: 8,
5257            section: &input,
5258        };
5259        let mut iter = CallFrameInstructionIter {
5260            input,
5261            address_encoding: None,
5262            parameters,
5263            vendor: Vendor::Default,
5264        };
5265
5266        assert_eq!(
5267            iter.next(),
5268            Ok(Some(CallFrameInstruction::ValExpression {
5269                register: Register(expected_reg),
5270                expression: expected_expression,
5271            }))
5272        );
5273
5274        assert_eq!(
5275            iter.next(),
5276            Ok(Some(CallFrameInstruction::AdvanceLoc {
5277                delta: u32::from(expected_delta),
5278            }))
5279        );
5280
5281        assert_eq!(iter.next(), Ok(None));
5282    }
5283
5284    #[test]
5285    fn test_call_frame_instruction_iter_err() {
5286        // DW_CFA_advance_loc1 without an operand.
5287        let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0);
5288
5289        let contents = section.get_contents().unwrap();
5290        let input = EndianSlice::new(&contents, BigEndian);
5291        let parameters = PointerEncodingParameters {
5292            bases: &SectionBaseAddresses::default(),
5293            func_base: None,
5294            address_size: 8,
5295            section: &EndianSlice::default(),
5296        };
5297        let mut iter = CallFrameInstructionIter {
5298            input,
5299            address_encoding: None,
5300            parameters,
5301            vendor: Vendor::Default,
5302        };
5303
5304        assert_eq!(
5305            iter.next().map_eof(&contents),
5306            Err(Error::UnexpectedEof(ReaderOffsetId(1)))
5307        );
5308        assert_eq!(iter.next(), Ok(None));
5309    }
5310
5311    fn assert_eval<'a, I>(
5312        mut initial_ctx: UnwindContext<usize>,
5313        expected_ctx: UnwindContext<usize>,
5314        cie: CommonInformationEntry<EndianSlice<'a, LittleEndian>>,
5315        fde: Option<FrameDescriptionEntry<EndianSlice<'a, LittleEndian>>>,
5316        instructions: I,
5317    ) where
5318        I: AsRef<[(Result<bool>, CallFrameInstruction<usize>)]>,
5319    {
5320        {
5321            let section = &DebugFrame::from(EndianSlice::default());
5322            let bases = &BaseAddresses::default();
5323            let mut table = match fde {
5324                Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde),
5325                None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie),
5326            };
5327            for (expected_result, instruction) in instructions.as_ref() {
5328                assert_eq!(*expected_result, table.evaluate(instruction.clone()));
5329            }
5330        }
5331
5332        assert_eq!(expected_ctx, initial_ctx);
5333    }
5334
5335    fn make_test_cie<'a>() -> CommonInformationEntry<EndianSlice<'a, LittleEndian>> {
5336        CommonInformationEntry {
5337            offset: 0,
5338            format: Format::Dwarf64,
5339            length: 0,
5340            return_address_register: Register(0),
5341            version: 4,
5342            address_size: mem::size_of::<usize>() as u8,
5343            initial_instructions: EndianSlice::new(&[], LittleEndian),
5344            augmentation: None,
5345            data_alignment_factor: 2,
5346            code_alignment_factor: 3,
5347        }
5348    }
5349
5350    #[test]
5351    fn test_eval_set_loc() {
5352        let cie = make_test_cie();
5353        let ctx = UnwindContext::new();
5354        let mut expected = ctx.clone();
5355        expected.row_mut().end_address = 42;
5356        let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })];
5357        assert_eval(ctx, expected, cie, None, instructions);
5358    }
5359
5360    #[test]
5361    fn test_eval_set_loc_backwards() {
5362        let cie = make_test_cie();
5363        let mut ctx = UnwindContext::new();
5364        ctx.row_mut().start_address = 999;
5365        let expected = ctx.clone();
5366        let instructions = [(
5367            Err(Error::InvalidAddressRange),
5368            CallFrameInstruction::SetLoc { address: 42 },
5369        )];
5370        assert_eval(ctx, expected, cie, None, instructions);
5371    }
5372
5373    #[test]
5374    fn test_eval_advance_loc() {
5375        let cie = make_test_cie();
5376        let mut ctx = UnwindContext::new();
5377        ctx.row_mut().start_address = 3;
5378        let mut expected = ctx.clone();
5379        expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor;
5380        let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })];
5381        assert_eval(ctx, expected, cie, None, instructions);
5382    }
5383
5384    #[test]
5385    fn test_eval_advance_loc_overflow_32() {
5386        let mut cie = make_test_cie();
5387        cie.address_size = 4;
5388        let mut ctx = UnwindContext::new();
5389        ctx.row_mut().start_address = u32::MAX.into();
5390        let expected = ctx.clone();
5391        let instructions = [(
5392            Err(Error::AddressOverflow),
5393            CallFrameInstruction::AdvanceLoc { delta: 42 },
5394        )];
5395        assert_eval(ctx, expected, cie, None, instructions);
5396    }
5397
5398    #[test]
5399    fn test_eval_advance_loc_overflow_64() {
5400        let mut cie = make_test_cie();
5401        cie.address_size = 8;
5402        let mut ctx = UnwindContext::new();
5403        ctx.row_mut().start_address = u64::MAX;
5404        let expected = ctx.clone();
5405        let instructions = [(
5406            Err(Error::AddressOverflow),
5407            CallFrameInstruction::AdvanceLoc { delta: 42 },
5408        )];
5409        assert_eval(ctx, expected, cie, None, instructions);
5410    }
5411
5412    #[test]
5413    fn test_eval_def_cfa() {
5414        let cie = make_test_cie();
5415        let ctx = UnwindContext::new();
5416        let mut expected = ctx.clone();
5417        expected.set_cfa(CfaRule::RegisterAndOffset {
5418            register: Register(42),
5419            offset: 36,
5420        });
5421        let instructions = [(
5422            Ok(false),
5423            CallFrameInstruction::DefCfa {
5424                register: Register(42),
5425                offset: 36,
5426            },
5427        )];
5428        assert_eval(ctx, expected, cie, None, instructions);
5429    }
5430
5431    #[test]
5432    fn test_eval_def_cfa_sf() {
5433        let cie = make_test_cie();
5434        let ctx = UnwindContext::new();
5435        let mut expected = ctx.clone();
5436        expected.set_cfa(CfaRule::RegisterAndOffset {
5437            register: Register(42),
5438            offset: 36 * cie.data_alignment_factor as i64,
5439        });
5440        let instructions = [(
5441            Ok(false),
5442            CallFrameInstruction::DefCfaSf {
5443                register: Register(42),
5444                factored_offset: 36,
5445            },
5446        )];
5447        assert_eval(ctx, expected, cie, None, instructions);
5448    }
5449
5450    #[test]
5451    fn test_eval_def_cfa_register() {
5452        let cie = make_test_cie();
5453        let mut ctx = UnwindContext::new();
5454        ctx.set_cfa(CfaRule::RegisterAndOffset {
5455            register: Register(3),
5456            offset: 8,
5457        });
5458        let mut expected = ctx.clone();
5459        expected.set_cfa(CfaRule::RegisterAndOffset {
5460            register: Register(42),
5461            offset: 8,
5462        });
5463        let instructions = [(
5464            Ok(false),
5465            CallFrameInstruction::DefCfaRegister {
5466                register: Register(42),
5467            },
5468        )];
5469        assert_eval(ctx, expected, cie, None, instructions);
5470    }
5471
5472    #[test]
5473    fn test_eval_def_cfa_register_invalid_context() {
5474        let cie = make_test_cie();
5475        let mut ctx = UnwindContext::new();
5476        ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5477            offset: 0,
5478            length: 0,
5479        }));
5480        let expected = ctx.clone();
5481        let instructions = [(
5482            Err(Error::CfiInstructionInInvalidContext),
5483            CallFrameInstruction::DefCfaRegister {
5484                register: Register(42),
5485            },
5486        )];
5487        assert_eval(ctx, expected, cie, None, instructions);
5488    }
5489
5490    #[test]
5491    fn test_eval_def_cfa_offset() {
5492        let cie = make_test_cie();
5493        let mut ctx = UnwindContext::new();
5494        ctx.set_cfa(CfaRule::RegisterAndOffset {
5495            register: Register(3),
5496            offset: 8,
5497        });
5498        let mut expected = ctx.clone();
5499        expected.set_cfa(CfaRule::RegisterAndOffset {
5500            register: Register(3),
5501            offset: 42,
5502        });
5503        let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })];
5504        assert_eval(ctx, expected, cie, None, instructions);
5505    }
5506
5507    #[test]
5508    fn test_eval_def_cfa_offset_invalid_context() {
5509        let cie = make_test_cie();
5510        let mut ctx = UnwindContext::new();
5511        ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5512            offset: 10,
5513            length: 11,
5514        }));
5515        let expected = ctx.clone();
5516        let instructions = [(
5517            Err(Error::CfiInstructionInInvalidContext),
5518            CallFrameInstruction::DefCfaOffset { offset: 1993 },
5519        )];
5520        assert_eval(ctx, expected, cie, None, instructions);
5521    }
5522
5523    #[test]
5524    fn test_eval_def_cfa_expression() {
5525        let expr = UnwindExpression {
5526            offset: 10,
5527            length: 11,
5528        };
5529        let cie = make_test_cie();
5530        let ctx = UnwindContext::new();
5531        let mut expected = ctx.clone();
5532        expected.set_cfa(CfaRule::Expression(expr));
5533        let instructions = [(
5534            Ok(false),
5535            CallFrameInstruction::DefCfaExpression { expression: expr },
5536        )];
5537        assert_eval(ctx, expected, cie, None, instructions);
5538    }
5539
5540    #[test]
5541    fn test_eval_undefined() {
5542        let cie = make_test_cie();
5543        let ctx = UnwindContext::new();
5544        let mut expected = ctx.clone();
5545        expected
5546            .set_register_rule(Register(5), RegisterRule::Undefined)
5547            .unwrap();
5548        let instructions = [(
5549            Ok(false),
5550            CallFrameInstruction::Undefined {
5551                register: Register(5),
5552            },
5553        )];
5554        assert_eval(ctx, expected, cie, None, instructions);
5555    }
5556
5557    #[test]
5558    fn test_eval_same_value() {
5559        let cie = make_test_cie();
5560        let ctx = UnwindContext::new();
5561        let mut expected = ctx.clone();
5562        expected
5563            .set_register_rule(Register(0), RegisterRule::SameValue)
5564            .unwrap();
5565        let instructions = [(
5566            Ok(false),
5567            CallFrameInstruction::SameValue {
5568                register: Register(0),
5569            },
5570        )];
5571        assert_eval(ctx, expected, cie, None, instructions);
5572    }
5573
5574    #[test]
5575    fn test_eval_offset() {
5576        let cie = make_test_cie();
5577        let ctx = UnwindContext::new();
5578        let mut expected = ctx.clone();
5579        expected
5580            .set_register_rule(
5581                Register(2),
5582                RegisterRule::Offset(3 * cie.data_alignment_factor),
5583            )
5584            .unwrap();
5585        let instructions = [(
5586            Ok(false),
5587            CallFrameInstruction::Offset {
5588                register: Register(2),
5589                factored_offset: 3,
5590            },
5591        )];
5592        assert_eval(ctx, expected, cie, None, instructions);
5593    }
5594
5595    #[test]
5596    fn test_eval_offset_extended_sf() {
5597        let cie = make_test_cie();
5598        let ctx = UnwindContext::new();
5599        let mut expected = ctx.clone();
5600        expected
5601            .set_register_rule(
5602                Register(4),
5603                RegisterRule::Offset(-3 * cie.data_alignment_factor),
5604            )
5605            .unwrap();
5606        let instructions = [(
5607            Ok(false),
5608            CallFrameInstruction::OffsetExtendedSf {
5609                register: Register(4),
5610                factored_offset: -3,
5611            },
5612        )];
5613        assert_eval(ctx, expected, cie, None, instructions);
5614    }
5615
5616    #[test]
5617    fn test_eval_val_offset() {
5618        let cie = make_test_cie();
5619        let ctx = UnwindContext::new();
5620        let mut expected = ctx.clone();
5621        expected
5622            .set_register_rule(
5623                Register(5),
5624                RegisterRule::ValOffset(7 * cie.data_alignment_factor),
5625            )
5626            .unwrap();
5627        let instructions = [(
5628            Ok(false),
5629            CallFrameInstruction::ValOffset {
5630                register: Register(5),
5631                factored_offset: 7,
5632            },
5633        )];
5634        assert_eval(ctx, expected, cie, None, instructions);
5635    }
5636
5637    #[test]
5638    fn test_eval_val_offset_sf() {
5639        let cie = make_test_cie();
5640        let ctx = UnwindContext::new();
5641        let mut expected = ctx.clone();
5642        expected
5643            .set_register_rule(
5644                Register(5),
5645                RegisterRule::ValOffset(-7 * cie.data_alignment_factor),
5646            )
5647            .unwrap();
5648        let instructions = [(
5649            Ok(false),
5650            CallFrameInstruction::ValOffsetSf {
5651                register: Register(5),
5652                factored_offset: -7,
5653            },
5654        )];
5655        assert_eval(ctx, expected, cie, None, instructions);
5656    }
5657
5658    #[test]
5659    fn test_eval_expression() {
5660        let expr = UnwindExpression {
5661            offset: 10,
5662            length: 11,
5663        };
5664        let cie = make_test_cie();
5665        let ctx = UnwindContext::new();
5666        let mut expected = ctx.clone();
5667        expected
5668            .set_register_rule(Register(9), RegisterRule::Expression(expr))
5669            .unwrap();
5670        let instructions = [(
5671            Ok(false),
5672            CallFrameInstruction::Expression {
5673                register: Register(9),
5674                expression: expr,
5675            },
5676        )];
5677        assert_eval(ctx, expected, cie, None, instructions);
5678    }
5679
5680    #[test]
5681    fn test_eval_val_expression() {
5682        let expr = UnwindExpression {
5683            offset: 10,
5684            length: 11,
5685        };
5686        let cie = make_test_cie();
5687        let ctx = UnwindContext::new();
5688        let mut expected = ctx.clone();
5689        expected
5690            .set_register_rule(Register(9), RegisterRule::ValExpression(expr))
5691            .unwrap();
5692        let instructions = [(
5693            Ok(false),
5694            CallFrameInstruction::ValExpression {
5695                register: Register(9),
5696                expression: expr,
5697            },
5698        )];
5699        assert_eval(ctx, expected, cie, None, instructions);
5700    }
5701
5702    #[test]
5703    fn test_eval_restore() {
5704        let cie = make_test_cie();
5705        let fde = FrameDescriptionEntry {
5706            offset: 0,
5707            format: Format::Dwarf64,
5708            length: 0,
5709            address_range: 0,
5710            augmentation: None,
5711            initial_address: 0,
5712            cie: cie.clone(),
5713            instructions: EndianSlice::new(&[], LittleEndian),
5714        };
5715
5716        let mut ctx = UnwindContext::new();
5717        ctx.set_register_rule(Register(0), RegisterRule::Offset(1))
5718            .unwrap();
5719        ctx.save_initial_rules().unwrap();
5720        let expected = ctx.clone();
5721        ctx.set_register_rule(Register(0), RegisterRule::Offset(2))
5722            .unwrap();
5723
5724        let instructions = [(
5725            Ok(false),
5726            CallFrameInstruction::Restore {
5727                register: Register(0),
5728            },
5729        )];
5730        assert_eval(ctx, expected, cie, Some(fde), instructions);
5731    }
5732
5733    #[test]
5734    fn test_eval_restore_havent_saved_initial_context() {
5735        let cie = make_test_cie();
5736        let ctx = UnwindContext::new();
5737        let expected = ctx.clone();
5738        let instructions = [(
5739            Err(Error::CfiInstructionInInvalidContext),
5740            CallFrameInstruction::Restore {
5741                register: Register(0),
5742            },
5743        )];
5744        assert_eval(ctx, expected, cie, None, instructions);
5745    }
5746
5747    #[test]
5748    fn test_eval_remember_state() {
5749        let cie = make_test_cie();
5750        let ctx = UnwindContext::new();
5751        let mut expected = ctx.clone();
5752        expected.push_row().unwrap();
5753        let instructions = [(Ok(false), CallFrameInstruction::RememberState)];
5754        assert_eval(ctx, expected, cie, None, instructions);
5755    }
5756
5757    #[test]
5758    fn test_eval_restore_state() {
5759        let cie = make_test_cie();
5760
5761        let mut ctx = UnwindContext::new();
5762        ctx.set_start_address(1);
5763        ctx.set_register_rule(Register(0), RegisterRule::SameValue)
5764            .unwrap();
5765        let mut expected = ctx.clone();
5766        ctx.push_row().unwrap();
5767        ctx.set_start_address(2);
5768        ctx.set_register_rule(Register(0), RegisterRule::Offset(16))
5769            .unwrap();
5770
5771        // Restore state should preserve current location.
5772        expected.set_start_address(2);
5773
5774        let instructions = [
5775            // First one pops just fine.
5776            (Ok(false), CallFrameInstruction::RestoreState),
5777            // Second pop would try to pop out of bounds.
5778            (
5779                Err(Error::PopWithEmptyStack),
5780                CallFrameInstruction::RestoreState,
5781            ),
5782        ];
5783
5784        assert_eval(ctx, expected, cie, None, instructions);
5785    }
5786
5787    #[test]
5788    fn test_eval_negate_ra_state() {
5789        let cie = make_test_cie();
5790        let ctx = UnwindContext::new();
5791        let mut expected = ctx.clone();
5792        expected
5793            .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1))
5794            .unwrap();
5795        let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)];
5796        assert_eval(ctx, expected, cie, None, instructions);
5797
5798        let cie = make_test_cie();
5799        let ctx = UnwindContext::new();
5800        let mut expected = ctx.clone();
5801        expected
5802            .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0))
5803            .unwrap();
5804        let instructions = [
5805            (Ok(false), CallFrameInstruction::NegateRaState),
5806            (Ok(false), CallFrameInstruction::NegateRaState),
5807        ];
5808        assert_eval(ctx, expected, cie, None, instructions);
5809
5810        // NegateRaState can't be used with other instructions.
5811        let cie = make_test_cie();
5812        let ctx = UnwindContext::new();
5813        let mut expected = ctx.clone();
5814        expected
5815            .set_register_rule(
5816                crate::AArch64::RA_SIGN_STATE,
5817                RegisterRule::Offset(cie.data_alignment_factor as i64),
5818            )
5819            .unwrap();
5820        let instructions = [
5821            (
5822                Ok(false),
5823                CallFrameInstruction::Offset {
5824                    register: crate::AArch64::RA_SIGN_STATE,
5825                    factored_offset: 1,
5826                },
5827            ),
5828            (
5829                Err(Error::CfiInstructionInInvalidContext),
5830                CallFrameInstruction::NegateRaState,
5831            ),
5832        ];
5833        assert_eval(ctx, expected, cie, None, instructions);
5834    }
5835
5836    #[test]
5837    fn test_eval_nop() {
5838        let cie = make_test_cie();
5839        let ctx = UnwindContext::new();
5840        let expected = ctx.clone();
5841        let instructions = [(Ok(false), CallFrameInstruction::Nop)];
5842        assert_eval(ctx, expected, cie, None, instructions);
5843    }
5844
5845    #[test]
5846    fn test_unwind_table_cie_no_rule() {
5847        let initial_instructions = Section::with_endian(Endian::Little)
5848            // The CFA is -12 from register 4.
5849            .D8(constants::DW_CFA_def_cfa_sf.0)
5850            .uleb(4)
5851            .sleb(-12)
5852            .append_repeated(constants::DW_CFA_nop.0, 4);
5853        let initial_instructions = initial_instructions.get_contents().unwrap();
5854
5855        let cie = CommonInformationEntry {
5856            offset: 0,
5857            length: 0,
5858            format: Format::Dwarf32,
5859            version: 4,
5860            augmentation: None,
5861            address_size: 8,
5862            code_alignment_factor: 1,
5863            data_alignment_factor: 1,
5864            return_address_register: Register(3),
5865            initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5866        };
5867
5868        let instructions = Section::with_endian(Endian::Little)
5869            // A bunch of nop padding.
5870            .append_repeated(constants::DW_CFA_nop.0, 8);
5871        let instructions = instructions.get_contents().unwrap();
5872
5873        let fde = FrameDescriptionEntry {
5874            offset: 0,
5875            length: 0,
5876            format: Format::Dwarf32,
5877            cie: cie.clone(),
5878            initial_address: 0,
5879            address_range: 100,
5880            augmentation: None,
5881            instructions: EndianSlice::new(&instructions, LittleEndian),
5882        };
5883
5884        let section = &DebugFrame::from(EndianSlice::default());
5885        let bases = &BaseAddresses::default();
5886        let mut ctx = Box::new(UnwindContext::new());
5887
5888        let mut table = fde
5889            .rows(section, bases, &mut ctx)
5890            .expect("Should run initial program OK");
5891        assert!(table.ctx.is_initialized);
5892        let expected_initial_rule = (Register(0), RegisterRule::Undefined);
5893        assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5894
5895        {
5896            let row = table.next_row().expect("Should evaluate first row OK");
5897            let expected = UnwindTableRow {
5898                start_address: 0,
5899                end_address: 100,
5900                saved_args_size: 0,
5901                cfa: CfaRule::RegisterAndOffset {
5902                    register: Register(4),
5903                    offset: -12,
5904                },
5905                registers: [].iter().collect(),
5906            };
5907            assert_eq!(Some(&expected), row);
5908        }
5909
5910        // All done!
5911        assert_eq!(Ok(None), table.next_row());
5912        assert_eq!(Ok(None), table.next_row());
5913    }
5914
5915    #[test]
5916    fn test_unwind_table_cie_single_rule() {
5917        let initial_instructions = Section::with_endian(Endian::Little)
5918            // The CFA is -12 from register 4.
5919            .D8(constants::DW_CFA_def_cfa_sf.0)
5920            .uleb(4)
5921            .sleb(-12)
5922            // Register 3 is 4 from the CFA.
5923            .D8(constants::DW_CFA_offset.0 | 3)
5924            .uleb(4)
5925            .append_repeated(constants::DW_CFA_nop.0, 4);
5926        let initial_instructions = initial_instructions.get_contents().unwrap();
5927
5928        let cie = CommonInformationEntry {
5929            offset: 0,
5930            length: 0,
5931            format: Format::Dwarf32,
5932            version: 4,
5933            augmentation: None,
5934            address_size: 8,
5935            code_alignment_factor: 1,
5936            data_alignment_factor: 1,
5937            return_address_register: Register(3),
5938            initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5939        };
5940
5941        let instructions = Section::with_endian(Endian::Little)
5942            // A bunch of nop padding.
5943            .append_repeated(constants::DW_CFA_nop.0, 8);
5944        let instructions = instructions.get_contents().unwrap();
5945
5946        let fde = FrameDescriptionEntry {
5947            offset: 0,
5948            length: 0,
5949            format: Format::Dwarf32,
5950            cie: cie.clone(),
5951            initial_address: 0,
5952            address_range: 100,
5953            augmentation: None,
5954            instructions: EndianSlice::new(&instructions, LittleEndian),
5955        };
5956
5957        let section = &DebugFrame::from(EndianSlice::default());
5958        let bases = &BaseAddresses::default();
5959        let mut ctx = Box::new(UnwindContext::new());
5960
5961        let mut table = fde
5962            .rows(section, bases, &mut ctx)
5963            .expect("Should run initial program OK");
5964        assert!(table.ctx.is_initialized);
5965        let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
5966        assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5967
5968        {
5969            let row = table.next_row().expect("Should evaluate first row OK");
5970            let expected = UnwindTableRow {
5971                start_address: 0,
5972                end_address: 100,
5973                saved_args_size: 0,
5974                cfa: CfaRule::RegisterAndOffset {
5975                    register: Register(4),
5976                    offset: -12,
5977                },
5978                registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(),
5979            };
5980            assert_eq!(Some(&expected), row);
5981        }
5982
5983        // All done!
5984        assert_eq!(Ok(None), table.next_row());
5985        assert_eq!(Ok(None), table.next_row());
5986    }
5987
5988    #[test]
5989    fn test_unwind_table_cie_invalid_rule() {
5990        let initial_instructions1 = Section::with_endian(Endian::Little)
5991            // Test that stack length is reset.
5992            .D8(constants::DW_CFA_remember_state.0)
5993            // Test that stack value is reset (different register from that used later).
5994            .D8(constants::DW_CFA_offset.0 | 4)
5995            .uleb(8)
5996            // Invalid due to missing operands.
5997            .D8(constants::DW_CFA_offset.0);
5998        let initial_instructions1 = initial_instructions1.get_contents().unwrap();
5999
6000        let cie1 = CommonInformationEntry {
6001            offset: 0,
6002            length: 0,
6003            format: Format::Dwarf32,
6004            version: 4,
6005            augmentation: None,
6006            address_size: 8,
6007            code_alignment_factor: 1,
6008            data_alignment_factor: 1,
6009            return_address_register: Register(3),
6010            initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian),
6011        };
6012
6013        let initial_instructions2 = Section::with_endian(Endian::Little)
6014            // Register 3 is 4 from the CFA.
6015            .D8(constants::DW_CFA_offset.0 | 3)
6016            .uleb(4)
6017            .append_repeated(constants::DW_CFA_nop.0, 4);
6018        let initial_instructions2 = initial_instructions2.get_contents().unwrap();
6019
6020        let cie2 = CommonInformationEntry {
6021            offset: 0,
6022            length: 0,
6023            format: Format::Dwarf32,
6024            version: 4,
6025            augmentation: None,
6026            address_size: 8,
6027            code_alignment_factor: 1,
6028            data_alignment_factor: 1,
6029            return_address_register: Register(3),
6030            initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian),
6031        };
6032
6033        let fde1 = FrameDescriptionEntry {
6034            offset: 0,
6035            length: 0,
6036            format: Format::Dwarf32,
6037            cie: cie1.clone(),
6038            initial_address: 0,
6039            address_range: 100,
6040            augmentation: None,
6041            instructions: EndianSlice::new(&[], LittleEndian),
6042        };
6043
6044        let fde2 = FrameDescriptionEntry {
6045            offset: 0,
6046            length: 0,
6047            format: Format::Dwarf32,
6048            cie: cie2.clone(),
6049            initial_address: 0,
6050            address_range: 100,
6051            augmentation: None,
6052            instructions: EndianSlice::new(&[], LittleEndian),
6053        };
6054
6055        let section = &DebugFrame::from(EndianSlice::default());
6056        let bases = &BaseAddresses::default();
6057        let mut ctx = Box::new(UnwindContext::new());
6058
6059        let table = fde1
6060            .rows(section, bases, &mut ctx)
6061            .map_eof(&initial_instructions1);
6062        assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4))));
6063        assert!(!ctx.is_initialized);
6064        assert_eq!(ctx.stack.len(), 2);
6065        assert_eq!(ctx.initial_rule, None);
6066
6067        let _table = fde2
6068            .rows(section, bases, &mut ctx)
6069            .expect("Should run initial program OK");
6070        assert!(ctx.is_initialized);
6071        assert_eq!(ctx.stack.len(), 1);
6072        let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
6073        assert_eq!(ctx.initial_rule, Some(expected_initial_rule));
6074    }
6075
6076    #[test]
6077    fn test_unwind_table_next_row() {
6078        #[allow(clippy::identity_op)]
6079        let initial_instructions = Section::with_endian(Endian::Little)
6080            // The CFA is -12 from register 4.
6081            .D8(constants::DW_CFA_def_cfa_sf.0)
6082            .uleb(4)
6083            .sleb(-12)
6084            // Register 0 is 8 from the CFA.
6085            .D8(constants::DW_CFA_offset.0 | 0)
6086            .uleb(8)
6087            // Register 3 is 4 from the CFA.
6088            .D8(constants::DW_CFA_offset.0 | 3)
6089            .uleb(4)
6090            .append_repeated(constants::DW_CFA_nop.0, 4);
6091        let initial_instructions = initial_instructions.get_contents().unwrap();
6092
6093        let cie = CommonInformationEntry {
6094            offset: 0,
6095            length: 0,
6096            format: Format::Dwarf32,
6097            version: 4,
6098            augmentation: None,
6099            address_size: 8,
6100            code_alignment_factor: 1,
6101            data_alignment_factor: 1,
6102            return_address_register: Register(3),
6103            initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
6104        };
6105
6106        let instructions = Section::with_endian(Endian::Little)
6107            // Initial instructions form a row, advance the address by 1.
6108            .D8(constants::DW_CFA_advance_loc1.0)
6109            .D8(1)
6110            // Register 0 is -16 from the CFA.
6111            .D8(constants::DW_CFA_offset_extended_sf.0)
6112            .uleb(0)
6113            .sleb(-16)
6114            // Finish this row, advance the address by 32.
6115            .D8(constants::DW_CFA_advance_loc1.0)
6116            .D8(32)
6117            // Register 3 is -4 from the CFA.
6118            .D8(constants::DW_CFA_offset_extended_sf.0)
6119            .uleb(3)
6120            .sleb(-4)
6121            // Finish this row, advance the address by 64.
6122            .D8(constants::DW_CFA_advance_loc1.0)
6123            .D8(64)
6124            // Register 5 is 4 from the CFA.
6125            .D8(constants::DW_CFA_offset.0 | 5)
6126            .uleb(4)
6127            // A bunch of nop padding.
6128            .append_repeated(constants::DW_CFA_nop.0, 8);
6129        let instructions = instructions.get_contents().unwrap();
6130
6131        let fde = FrameDescriptionEntry {
6132            offset: 0,
6133            length: 0,
6134            format: Format::Dwarf32,
6135            cie: cie.clone(),
6136            initial_address: 0,
6137            address_range: 100,
6138            augmentation: None,
6139            instructions: EndianSlice::new(&instructions, LittleEndian),
6140        };
6141
6142        let section = &DebugFrame::from(EndianSlice::default());
6143        let bases = &BaseAddresses::default();
6144        let mut ctx = Box::new(UnwindContext::new());
6145
6146        let mut table = fde
6147            .rows(section, bases, &mut ctx)
6148            .expect("Should run initial program OK");
6149        assert!(table.ctx.is_initialized);
6150        assert!(table.ctx.initial_rule.is_none());
6151        let expected_initial_rules: RegisterRuleMap<_> = [
6152            (Register(0), RegisterRule::Offset(8)),
6153            (Register(3), RegisterRule::Offset(4)),
6154        ]
6155        .iter()
6156        .collect();
6157        assert_eq!(table.ctx.stack[0].registers, expected_initial_rules);
6158
6159        {
6160            let row = table.next_row().expect("Should evaluate first row OK");
6161            let expected = UnwindTableRow {
6162                start_address: 0,
6163                end_address: 1,
6164                saved_args_size: 0,
6165                cfa: CfaRule::RegisterAndOffset {
6166                    register: Register(4),
6167                    offset: -12,
6168                },
6169                registers: [
6170                    (Register(0), RegisterRule::Offset(8)),
6171                    (Register(3), RegisterRule::Offset(4)),
6172                ]
6173                .iter()
6174                .collect(),
6175            };
6176            assert_eq!(Some(&expected), row);
6177        }
6178
6179        {
6180            let row = table.next_row().expect("Should evaluate second row OK");
6181            let expected = UnwindTableRow {
6182                start_address: 1,
6183                end_address: 33,
6184                saved_args_size: 0,
6185                cfa: CfaRule::RegisterAndOffset {
6186                    register: Register(4),
6187                    offset: -12,
6188                },
6189                registers: [
6190                    (Register(0), RegisterRule::Offset(-16)),
6191                    (Register(3), RegisterRule::Offset(4)),
6192                ]
6193                .iter()
6194                .collect(),
6195            };
6196            assert_eq!(Some(&expected), row);
6197        }
6198
6199        {
6200            let row = table.next_row().expect("Should evaluate third row OK");
6201            let expected = UnwindTableRow {
6202                start_address: 33,
6203                end_address: 97,
6204                saved_args_size: 0,
6205                cfa: CfaRule::RegisterAndOffset {
6206                    register: Register(4),
6207                    offset: -12,
6208                },
6209                registers: [
6210                    (Register(0), RegisterRule::Offset(-16)),
6211                    (Register(3), RegisterRule::Offset(-4)),
6212                ]
6213                .iter()
6214                .collect(),
6215            };
6216            assert_eq!(Some(&expected), row);
6217        }
6218
6219        {
6220            let row = table.next_row().expect("Should evaluate fourth row OK");
6221            let expected = UnwindTableRow {
6222                start_address: 97,
6223                end_address: 100,
6224                saved_args_size: 0,
6225                cfa: CfaRule::RegisterAndOffset {
6226                    register: Register(4),
6227                    offset: -12,
6228                },
6229                registers: [
6230                    (Register(0), RegisterRule::Offset(-16)),
6231                    (Register(3), RegisterRule::Offset(-4)),
6232                    (Register(5), RegisterRule::Offset(4)),
6233                ]
6234                .iter()
6235                .collect(),
6236            };
6237            assert_eq!(Some(&expected), row);
6238        }
6239
6240        // All done!
6241        assert_eq!(Ok(None), table.next_row());
6242        assert_eq!(Ok(None), table.next_row());
6243    }
6244
6245    #[test]
6246    fn test_unwind_info_for_address_ok() {
6247        let instrs1 = Section::with_endian(Endian::Big)
6248            // The CFA is -12 from register 4.
6249            .D8(constants::DW_CFA_def_cfa_sf.0)
6250            .uleb(4)
6251            .sleb(-12);
6252        let instrs1 = instrs1.get_contents().unwrap();
6253
6254        let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
6255
6256        let instrs3 = Section::with_endian(Endian::Big)
6257            // Initial instructions form a row, advance the address by 100.
6258            .D8(constants::DW_CFA_advance_loc1.0)
6259            .D8(100)
6260            // Register 0 is -16 from the CFA.
6261            .D8(constants::DW_CFA_offset_extended_sf.0)
6262            .uleb(0)
6263            .sleb(-16);
6264        let instrs3 = instrs3.get_contents().unwrap();
6265
6266        let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
6267
6268        let mut cie1 = CommonInformationEntry {
6269            offset: 0,
6270            length: 0,
6271            format: Format::Dwarf32,
6272            version: 4,
6273            augmentation: None,
6274            address_size: 8,
6275            code_alignment_factor: 1,
6276            data_alignment_factor: 1,
6277            return_address_register: Register(3),
6278            initial_instructions: EndianSlice::new(&instrs1, BigEndian),
6279        };
6280
6281        let mut cie2 = CommonInformationEntry {
6282            offset: 0,
6283            length: 0,
6284            format: Format::Dwarf32,
6285            version: 4,
6286            augmentation: None,
6287            address_size: 4,
6288            code_alignment_factor: 1,
6289            data_alignment_factor: 1,
6290            return_address_register: Register(1),
6291            initial_instructions: EndianSlice::new(&instrs2, BigEndian),
6292        };
6293
6294        let cie1_location = Label::new();
6295        let cie2_location = Label::new();
6296
6297        // Write the CIEs first so that their length gets set before we clone
6298        // them into the FDEs and our equality assertions down the line end up
6299        // with all the CIEs always having he correct length.
6300        let kind = debug_frame_be();
6301        let section = Section::with_endian(kind.endian())
6302            .mark(&cie1_location)
6303            .cie(kind, None, &mut cie1)
6304            .mark(&cie2_location)
6305            .cie(kind, None, &mut cie2);
6306
6307        let mut fde1 = FrameDescriptionEntry {
6308            offset: 0,
6309            length: 0,
6310            format: Format::Dwarf32,
6311            cie: cie1.clone(),
6312            initial_address: 0xfeed_beef,
6313            address_range: 200,
6314            augmentation: None,
6315            instructions: EndianSlice::new(&instrs3, BigEndian),
6316        };
6317
6318        let mut fde2 = FrameDescriptionEntry {
6319            offset: 0,
6320            length: 0,
6321            format: Format::Dwarf32,
6322            cie: cie2.clone(),
6323            initial_address: 0xfeed_face,
6324            address_range: 9000,
6325            augmentation: None,
6326            instructions: EndianSlice::new(&instrs4, BigEndian),
6327        };
6328
6329        let section =
6330            section
6331                .fde(kind, &cie1_location, &mut fde1)
6332                .fde(kind, &cie2_location, &mut fde2);
6333        section.start().set_const(0);
6334
6335        let contents = section.get_contents().unwrap();
6336        let debug_frame = kind.section(&contents);
6337
6338        // Get the second row of the unwind table in `instrs3`.
6339        let bases = Default::default();
6340        let mut ctx = Box::new(UnwindContext::new());
6341        let result = debug_frame.unwind_info_for_address(
6342            &bases,
6343            &mut ctx,
6344            0xfeed_beef + 150,
6345            DebugFrame::cie_from_offset,
6346        );
6347        assert!(result.is_ok());
6348        let unwind_info = result.unwrap();
6349
6350        assert_eq!(
6351            *unwind_info,
6352            UnwindTableRow {
6353                start_address: fde1.initial_address() + 100,
6354                end_address: fde1.end_address(),
6355                saved_args_size: 0,
6356                cfa: CfaRule::RegisterAndOffset {
6357                    register: Register(4),
6358                    offset: -12,
6359                },
6360                registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(),
6361            }
6362        );
6363    }
6364
6365    #[test]
6366    fn test_unwind_info_for_address_not_found() {
6367        let debug_frame = DebugFrame::new(&[], NativeEndian);
6368        let bases = Default::default();
6369        let mut ctx = Box::new(UnwindContext::new());
6370        let result = debug_frame.unwind_info_for_address(
6371            &bases,
6372            &mut ctx,
6373            0xbadb_ad99,
6374            DebugFrame::cie_from_offset,
6375        );
6376        assert!(result.is_err());
6377        assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
6378    }
6379
6380    #[test]
6381    fn test_eh_frame_hdr_unknown_version() {
6382        let bases = BaseAddresses::default();
6383        let buf = &[42];
6384        let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8);
6385        assert!(result.is_err());
6386        assert_eq!(result.unwrap_err(), Error::UnknownVersion(42));
6387    }
6388
6389    #[test]
6390    fn test_eh_frame_hdr_omit_ehptr() {
6391        let section = Section::with_endian(Endian::Little)
6392            .L8(1)
6393            .L8(0xff)
6394            .L8(0x03)
6395            .L8(0x0b)
6396            .L32(2)
6397            .L32(10)
6398            .L32(1)
6399            .L32(20)
6400            .L32(2)
6401            .L32(0);
6402        let section = section.get_contents().unwrap();
6403        let bases = BaseAddresses::default();
6404        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6405        assert!(result.is_err());
6406        assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding);
6407    }
6408
6409    #[test]
6410    fn test_eh_frame_hdr_omit_count() {
6411        let section = Section::with_endian(Endian::Little)
6412            .L8(1)
6413            .L8(0x0b)
6414            .L8(0xff)
6415            .L8(0x0b)
6416            .L32(0x12345);
6417        let section = section.get_contents().unwrap();
6418        let bases = BaseAddresses::default();
6419        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6420        assert!(result.is_ok());
6421        let result = result.unwrap();
6422        assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6423        assert!(result.table().is_none());
6424    }
6425
6426    #[test]
6427    fn test_eh_frame_hdr_omit_table() {
6428        let section = Section::with_endian(Endian::Little)
6429            .L8(1)
6430            .L8(0x0b)
6431            .L8(0x03)
6432            .L8(0xff)
6433            .L32(0x12345)
6434            .L32(2);
6435        let section = section.get_contents().unwrap();
6436        let bases = BaseAddresses::default();
6437        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6438        assert!(result.is_ok());
6439        let result = result.unwrap();
6440        assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6441        assert!(result.table().is_none());
6442    }
6443
6444    #[test]
6445    fn test_eh_frame_hdr_varlen_table() {
6446        let section = Section::with_endian(Endian::Little)
6447            .L8(1)
6448            .L8(0x0b)
6449            .L8(0x03)
6450            .L8(0x01)
6451            .L32(0x12345)
6452            .L32(2);
6453        let section = section.get_contents().unwrap();
6454        let bases = BaseAddresses::default();
6455        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6456        assert!(result.is_ok());
6457        let result = result.unwrap();
6458        assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6459        let table = result.table();
6460        assert!(table.is_some());
6461        let table = table.unwrap();
6462        assert_eq!(
6463            table.lookup(0, &bases),
6464            Err(Error::VariableLengthSearchTable)
6465        );
6466    }
6467
6468    #[test]
6469    fn test_eh_frame_hdr_indirect_length() {
6470        let section = Section::with_endian(Endian::Little)
6471            .L8(1)
6472            .L8(0x0b)
6473            .L8(0x83)
6474            .L8(0x0b)
6475            .L32(0x12345)
6476            .L32(2);
6477        let section = section.get_contents().unwrap();
6478        let bases = BaseAddresses::default();
6479        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6480        assert!(result.is_err());
6481        assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding);
6482    }
6483
6484    #[test]
6485    fn test_eh_frame_hdr_indirect_ptrs() {
6486        let section = Section::with_endian(Endian::Little)
6487            .L8(1)
6488            .L8(0x8b)
6489            .L8(0x03)
6490            .L8(0x8b)
6491            .L32(0x12345)
6492            .L32(2)
6493            .L32(10)
6494            .L32(1)
6495            .L32(20)
6496            .L32(2);
6497        let section = section.get_contents().unwrap();
6498        let bases = BaseAddresses::default();
6499        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6500        assert!(result.is_ok());
6501        let result = result.unwrap();
6502        assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345));
6503        let table = result.table();
6504        assert!(table.is_some());
6505        let table = table.unwrap();
6506        assert_eq!(
6507            table.lookup(0, &bases),
6508            Err(Error::UnsupportedPointerEncoding)
6509        );
6510    }
6511
6512    #[test]
6513    fn test_eh_frame_hdr_good() {
6514        let section = Section::with_endian(Endian::Little)
6515            .L8(1)
6516            .L8(0x0b)
6517            .L8(0x03)
6518            .L8(0x0b)
6519            .L32(0x12345)
6520            .L32(2)
6521            .L32(10)
6522            .L32(1)
6523            .L32(20)
6524            .L32(2);
6525        let section = section.get_contents().unwrap();
6526        let bases = BaseAddresses::default();
6527        let result = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6528        assert!(result.is_ok());
6529        let result = result.unwrap();
6530        assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6531        let table = result.table();
6532        assert!(table.is_some());
6533        let table = table.unwrap();
6534        assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1)));
6535        assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1)));
6536        assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1)));
6537        assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1)));
6538        assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1)));
6539        assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2)));
6540        assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2)));
6541        assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2)));
6542    }
6543
6544    #[test]
6545    fn test_eh_frame_fde_for_address_good() {
6546        // First, setup eh_frame
6547        // Write the CIE first so that its length gets set before we clone it
6548        // into the FDE.
6549        let mut cie = make_test_cie();
6550        cie.format = Format::Dwarf32;
6551        cie.version = 1;
6552
6553        let start_of_cie = Label::new();
6554        let end_of_cie = Label::new();
6555
6556        let kind = eh_frame_le();
6557        let section = Section::with_endian(kind.endian())
6558            .append_repeated(0, 16)
6559            .mark(&start_of_cie)
6560            .cie(kind, None, &mut cie)
6561            .mark(&end_of_cie);
6562
6563        let mut fde1 = FrameDescriptionEntry {
6564            offset: 0,
6565            length: 0,
6566            format: Format::Dwarf32,
6567            cie: cie.clone(),
6568            initial_address: 9,
6569            address_range: 4,
6570            augmentation: None,
6571            instructions: EndianSlice::new(&[], LittleEndian),
6572        };
6573        let mut fde2 = FrameDescriptionEntry {
6574            offset: 0,
6575            length: 0,
6576            format: Format::Dwarf32,
6577            cie: cie.clone(),
6578            initial_address: 20,
6579            address_range: 8,
6580            augmentation: None,
6581            instructions: EndianSlice::new(&[], LittleEndian),
6582        };
6583
6584        let start_of_fde1 = Label::new();
6585        let start_of_fde2 = Label::new();
6586
6587        let section = section
6588            // +4 for the FDE length before the CIE offset.
6589            .mark(&start_of_fde1)
6590            .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1)
6591            .mark(&start_of_fde2)
6592            .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2);
6593
6594        section.start().set_const(0);
6595        let section = section.get_contents().unwrap();
6596        let eh_frame = kind.section(&section);
6597
6598        // Setup eh_frame_hdr
6599        let section = Section::with_endian(kind.endian())
6600            .L8(1)
6601            .L8(0x0b)
6602            .L8(0x03)
6603            .L8(0x0b)
6604            .L32(0x12345)
6605            .L32(2)
6606            .L32(10)
6607            .L32(0x12345 + start_of_fde1.value().unwrap() as u32)
6608            .L32(20)
6609            .L32(0x12345 + start_of_fde2.value().unwrap() as u32);
6610
6611        let section = section.get_contents().unwrap();
6612        let bases = BaseAddresses::default();
6613        let eh_frame_hdr = EhFrameHdr::new(&section, LittleEndian).parse(&bases, 8);
6614        assert!(eh_frame_hdr.is_ok());
6615        let eh_frame_hdr = eh_frame_hdr.unwrap();
6616
6617        let table = eh_frame_hdr.table();
6618        assert!(table.is_some());
6619        let table = table.unwrap();
6620
6621        let bases = Default::default();
6622        let mut iter = table.iter(&bases);
6623        assert_eq!(
6624            iter.next(),
6625            Ok(Some((
6626                Pointer::Direct(10),
6627                Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6628            )))
6629        );
6630        assert_eq!(
6631            iter.next(),
6632            Ok(Some((
6633                Pointer::Direct(20),
6634                Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6635            )))
6636        );
6637        assert_eq!(iter.next(), Ok(None));
6638
6639        assert_eq!(
6640            table.iter(&bases).nth(0),
6641            Ok(Some((
6642                Pointer::Direct(10),
6643                Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6644            )))
6645        );
6646
6647        assert_eq!(
6648            table.iter(&bases).nth(1),
6649            Ok(Some((
6650                Pointer::Direct(20),
6651                Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6652            )))
6653        );
6654        assert_eq!(table.iter(&bases).nth(2), Ok(None));
6655
6656        let f = |_: &_, _: &_, o: EhFrameOffset| {
6657            assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6658            Ok(cie.clone())
6659        };
6660        assert_eq!(
6661            table.fde_for_address(&eh_frame, &bases, 9, f),
6662            Ok(fde1.clone())
6663        );
6664        assert_eq!(
6665            table.fde_for_address(&eh_frame, &bases, 10, f),
6666            Ok(fde1.clone())
6667        );
6668        assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1));
6669        assert_eq!(
6670            table.fde_for_address(&eh_frame, &bases, 19, f),
6671            Err(Error::NoUnwindInfoForAddress)
6672        );
6673        assert_eq!(
6674            table.fde_for_address(&eh_frame, &bases, 20, f),
6675            Ok(fde2.clone())
6676        );
6677        assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2));
6678        assert_eq!(
6679            table.fde_for_address(&eh_frame, &bases, 100_000, f),
6680            Err(Error::NoUnwindInfoForAddress)
6681        );
6682    }
6683
6684    #[test]
6685    fn test_eh_frame_stops_at_zero_length() {
6686        let mut cie = make_test_cie();
6687        let kind = eh_frame_le();
6688        let section = Section::with_endian(Endian::Little)
6689            .L32(0)
6690            .cie(kind, None, &mut cie)
6691            .L32(0);
6692        let contents = section.get_contents().unwrap();
6693        let eh_frame = kind.section(&contents);
6694        let bases = Default::default();
6695
6696        let mut entries = eh_frame.entries(&bases);
6697        assert_eq!(entries.next(), Ok(None));
6698
6699        assert_eq!(
6700            eh_frame.cie_from_offset(&bases, EhFrameOffset(0)),
6701            Err(Error::NoEntryAtGivenOffset)
6702        );
6703    }
6704
6705    #[test]
6706    fn test_debug_frame_skips_zero_length() {
6707        let mut cie = make_test_cie();
6708        let kind = debug_frame_le();
6709        let section = Section::with_endian(Endian::Little)
6710            .L32(0)
6711            .cie(kind, None, &mut cie)
6712            .L32(0);
6713        let contents = section.get_contents().unwrap();
6714        let debug_frame = kind.section(&contents);
6715        let bases = Default::default();
6716
6717        let mut entries = debug_frame.entries(&bases);
6718        assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie))));
6719        assert_eq!(entries.next(), Ok(None));
6720
6721        assert_eq!(
6722            debug_frame.cie_from_offset(&bases, DebugFrameOffset(0)),
6723            Err(Error::NoEntryAtGivenOffset)
6724        );
6725    }
6726
6727    fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result<usize> {
6728        let mut fde = FrameDescriptionEntry {
6729            offset: 0,
6730            length: 0,
6731            format: Format::Dwarf64,
6732            cie: make_test_cie(),
6733            initial_address: 0xfeed_beef,
6734            address_range: 39,
6735            augmentation: None,
6736            instructions: EndianSlice::new(&[], LittleEndian),
6737        };
6738
6739        let kind = eh_frame_le();
6740        let section = Section::with_endian(kind.endian())
6741            .append_bytes(buf)
6742            .fde(kind, cie_offset as u64, &mut fde)
6743            .append_bytes(buf);
6744
6745        let section = section.get_contents().unwrap();
6746        let eh_frame = kind.section(&section);
6747        let input = &mut EndianSlice::new(&section[buf.len()..], LittleEndian);
6748
6749        let bases = Default::default();
6750        match parse_cfi_entry(&bases, &eh_frame, input) {
6751            Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0),
6752            Err(e) => Err(e),
6753            otherwise => panic!("Unexpected result: {:#?}", otherwise),
6754        }
6755    }
6756
6757    #[test]
6758    fn test_eh_frame_resolve_cie_offset_ok() {
6759        let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6760        let cie_offset = 2;
6761        // + 4 for size of length field
6762        assert_eq!(
6763            resolve_cie_offset(&buf, buf.len() + 4 - cie_offset),
6764            Ok(cie_offset)
6765        );
6766    }
6767
6768    #[test]
6769    fn test_eh_frame_resolve_cie_offset_out_of_bounds() {
6770        let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6771        assert_eq!(
6772            resolve_cie_offset(&buf, buf.len() + 4 + 2),
6773            Err(Error::OffsetOutOfBounds)
6774        );
6775    }
6776
6777    #[test]
6778    fn test_eh_frame_resolve_cie_offset_underflow() {
6779        let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6780        assert_eq!(
6781            resolve_cie_offset(&buf, usize::MAX),
6782            Err(Error::OffsetOutOfBounds)
6783        );
6784    }
6785
6786    #[test]
6787    fn test_eh_frame_fde_ok() {
6788        let mut cie = make_test_cie();
6789        cie.format = Format::Dwarf32;
6790        cie.version = 1;
6791
6792        let start_of_cie = Label::new();
6793        let end_of_cie = Label::new();
6794
6795        // Write the CIE first so that its length gets set before we clone it
6796        // into the FDE.
6797        let kind = eh_frame_le();
6798        let section = Section::with_endian(kind.endian())
6799            .append_repeated(0, 16)
6800            .mark(&start_of_cie)
6801            .cie(kind, None, &mut cie)
6802            .mark(&end_of_cie);
6803
6804        let mut fde = FrameDescriptionEntry {
6805            offset: 0,
6806            length: 0,
6807            format: Format::Dwarf32,
6808            cie: cie.clone(),
6809            initial_address: 0xfeed_beef,
6810            address_range: 999,
6811            augmentation: None,
6812            instructions: EndianSlice::new(&[], LittleEndian),
6813        };
6814
6815        let section = section
6816            // +4 for the FDE length before the CIE offset.
6817            .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde);
6818
6819        section.start().set_const(0);
6820        let section = section.get_contents().unwrap();
6821        let eh_frame = kind.section(&section);
6822        let section = EndianSlice::new(&section, LittleEndian);
6823
6824        let mut offset = None;
6825        let result = parse_fde(
6826            eh_frame,
6827            &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6828            |_, _, o| {
6829                offset = Some(o);
6830                assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6831                Ok(cie.clone())
6832            },
6833        );
6834        match result {
6835            Ok(actual) => assert_eq!(actual, fde),
6836            otherwise => panic!("Unexpected result {:?}", otherwise),
6837        }
6838        assert!(offset.is_some());
6839    }
6840
6841    #[test]
6842    fn test_eh_frame_fde_out_of_bounds() {
6843        let mut cie = make_test_cie();
6844        cie.version = 1;
6845
6846        let end_of_cie = Label::new();
6847
6848        let mut fde = FrameDescriptionEntry {
6849            offset: 0,
6850            length: 0,
6851            format: Format::Dwarf64,
6852            cie: cie.clone(),
6853            initial_address: 0xfeed_beef,
6854            address_range: 999,
6855            augmentation: None,
6856            instructions: EndianSlice::new(&[], LittleEndian),
6857        };
6858
6859        let kind = eh_frame_le();
6860        let section = Section::with_endian(kind.endian())
6861            .cie(kind, None, &mut cie)
6862            .mark(&end_of_cie)
6863            .fde(kind, 99_999_999_999_999, &mut fde);
6864
6865        section.start().set_const(0);
6866        let section = section.get_contents().unwrap();
6867        let eh_frame = kind.section(&section);
6868        let section = EndianSlice::new(&section, LittleEndian);
6869
6870        let result = parse_fde(
6871            eh_frame,
6872            &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6873            UnwindSection::cie_from_offset,
6874        );
6875        assert_eq!(result, Err(Error::OffsetOutOfBounds));
6876    }
6877
6878    #[test]
6879    fn test_augmentation_parse_not_z_augmentation() {
6880        let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian);
6881        let bases = Default::default();
6882        let address_size = 8;
6883        let section = EhFrame::new(&[], NativeEndian);
6884        let input = &mut EndianSlice::new(&[], NativeEndian);
6885        assert_eq!(
6886            Augmentation::parse(augmentation, &bases, address_size, &section, input),
6887            Err(Error::UnknownAugmentation)
6888        );
6889    }
6890
6891    #[test]
6892    fn test_augmentation_parse_just_signal_trampoline() {
6893        let aug_str = &mut EndianSlice::new(b"S", LittleEndian);
6894        let bases = Default::default();
6895        let address_size = 8;
6896        let section = EhFrame::new(&[], LittleEndian);
6897        let input = &mut EndianSlice::new(&[], LittleEndian);
6898
6899        let augmentation = Augmentation {
6900            is_signal_trampoline: true,
6901            ..Default::default()
6902        };
6903
6904        assert_eq!(
6905            Augmentation::parse(aug_str, &bases, address_size, &section, input),
6906            Ok(augmentation)
6907        );
6908    }
6909
6910    #[test]
6911    fn test_augmentation_parse_unknown_part_of_z_augmentation() {
6912        // The 'Z' character is not defined by the z-style augmentation.
6913        let bases = Default::default();
6914        let address_size = 8;
6915        let section = Section::with_endian(Endian::Little)
6916            .uleb(4)
6917            .append_repeated(4, 4)
6918            .get_contents()
6919            .unwrap();
6920        let section = EhFrame::new(&section, LittleEndian);
6921        let input = &mut section.section().clone();
6922        let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian);
6923        assert_eq!(
6924            Augmentation::parse(augmentation, &bases, address_size, &section, input),
6925            Err(Error::UnknownAugmentation)
6926        );
6927    }
6928
6929    #[test]
6930    #[allow(non_snake_case)]
6931    fn test_augmentation_parse_L() {
6932        let bases = Default::default();
6933        let address_size = 8;
6934        let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6935
6936        let section = Section::with_endian(Endian::Little)
6937            .uleb(1)
6938            .D8(constants::DW_EH_PE_uleb128.0)
6939            .append_bytes(&rest)
6940            .get_contents()
6941            .unwrap();
6942        let section = EhFrame::new(&section, LittleEndian);
6943        let input = &mut section.section().clone();
6944        let aug_str = &mut EndianSlice::new(b"zL", LittleEndian);
6945
6946        let augmentation = Augmentation {
6947            lsda: Some(constants::DW_EH_PE_uleb128),
6948            ..Default::default()
6949        };
6950
6951        assert_eq!(
6952            Augmentation::parse(aug_str, &bases, address_size, &section, input),
6953            Ok(augmentation)
6954        );
6955        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6956    }
6957
6958    #[test]
6959    #[allow(non_snake_case)]
6960    fn test_augmentation_parse_P() {
6961        let bases = Default::default();
6962        let address_size = 8;
6963        let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6964
6965        let section = Section::with_endian(Endian::Little)
6966            .uleb(9)
6967            .D8(constants::DW_EH_PE_udata8.0)
6968            .L64(0xf00d_f00d)
6969            .append_bytes(&rest)
6970            .get_contents()
6971            .unwrap();
6972        let section = EhFrame::new(&section, LittleEndian);
6973        let input = &mut section.section().clone();
6974        let aug_str = &mut EndianSlice::new(b"zP", LittleEndian);
6975
6976        let augmentation = Augmentation {
6977            personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))),
6978            ..Default::default()
6979        };
6980
6981        assert_eq!(
6982            Augmentation::parse(aug_str, &bases, address_size, &section, input),
6983            Ok(augmentation)
6984        );
6985        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6986    }
6987
6988    #[test]
6989    #[allow(non_snake_case)]
6990    fn test_augmentation_parse_R() {
6991        let bases = Default::default();
6992        let address_size = 8;
6993        let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6994
6995        let section = Section::with_endian(Endian::Little)
6996            .uleb(1)
6997            .D8(constants::DW_EH_PE_udata4.0)
6998            .append_bytes(&rest)
6999            .get_contents()
7000            .unwrap();
7001        let section = EhFrame::new(&section, LittleEndian);
7002        let input = &mut section.section().clone();
7003        let aug_str = &mut EndianSlice::new(b"zR", LittleEndian);
7004
7005        let augmentation = Augmentation {
7006            fde_address_encoding: Some(constants::DW_EH_PE_udata4),
7007            ..Default::default()
7008        };
7009
7010        assert_eq!(
7011            Augmentation::parse(aug_str, &bases, address_size, &section, input),
7012            Ok(augmentation)
7013        );
7014        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7015    }
7016
7017    #[test]
7018    #[allow(non_snake_case)]
7019    fn test_augmentation_parse_S() {
7020        let bases = Default::default();
7021        let address_size = 8;
7022        let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7023
7024        let section = Section::with_endian(Endian::Little)
7025            .uleb(0)
7026            .append_bytes(&rest)
7027            .get_contents()
7028            .unwrap();
7029        let section = EhFrame::new(&section, LittleEndian);
7030        let input = &mut section.section().clone();
7031        let aug_str = &mut EndianSlice::new(b"zS", LittleEndian);
7032
7033        let augmentation = Augmentation {
7034            is_signal_trampoline: true,
7035            ..Default::default()
7036        };
7037
7038        assert_eq!(
7039            Augmentation::parse(aug_str, &bases, address_size, &section, input),
7040            Ok(augmentation)
7041        );
7042        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7043    }
7044
7045    #[test]
7046    fn test_augmentation_parse_all() {
7047        let bases = Default::default();
7048        let address_size = 8;
7049        let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7050
7051        let section = Section::with_endian(Endian::Little)
7052            .uleb(1 + 9 + 1)
7053            // L
7054            .D8(constants::DW_EH_PE_uleb128.0)
7055            // P
7056            .D8(constants::DW_EH_PE_udata8.0)
7057            .L64(0x1bad_f00d)
7058            // R
7059            .D8(constants::DW_EH_PE_uleb128.0)
7060            .append_bytes(&rest)
7061            .get_contents()
7062            .unwrap();
7063        let section = EhFrame::new(&section, LittleEndian);
7064        let input = &mut section.section().clone();
7065        let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian);
7066
7067        let augmentation = Augmentation {
7068            lsda: Some(constants::DW_EH_PE_uleb128),
7069            personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))),
7070            fde_address_encoding: Some(constants::DW_EH_PE_uleb128),
7071            is_signal_trampoline: true,
7072        };
7073
7074        assert_eq!(
7075            Augmentation::parse(aug_str, &bases, address_size, &section, input),
7076            Ok(augmentation)
7077        );
7078        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7079    }
7080
7081    #[test]
7082    fn test_eh_frame_fde_no_augmentation() {
7083        let instrs = [1, 2, 3, 4];
7084        let cie_offset = 1;
7085
7086        let mut cie = make_test_cie();
7087        cie.format = Format::Dwarf32;
7088        cie.version = 1;
7089
7090        let mut fde = FrameDescriptionEntry {
7091            offset: 0,
7092            length: 0,
7093            format: Format::Dwarf32,
7094            cie: cie.clone(),
7095            initial_address: 0xfeed_face,
7096            address_range: 9000,
7097            augmentation: None,
7098            instructions: EndianSlice::new(&instrs, LittleEndian),
7099        };
7100
7101        let rest = [1, 2, 3, 4];
7102
7103        let kind = eh_frame_le();
7104        let section = Section::with_endian(kind.endian())
7105            .fde(kind, cie_offset, &mut fde)
7106            .append_bytes(&rest)
7107            .get_contents()
7108            .unwrap();
7109        let section = kind.section(&section);
7110        let input = &mut section.section().clone();
7111
7112        let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7113        assert_eq!(result, Ok(fde));
7114        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7115    }
7116
7117    #[test]
7118    fn test_eh_frame_fde_empty_augmentation() {
7119        let instrs = [1, 2, 3, 4];
7120        let cie_offset = 1;
7121
7122        let mut cie = make_test_cie();
7123        cie.format = Format::Dwarf32;
7124        cie.version = 1;
7125        cie.augmentation = Some(Augmentation::default());
7126
7127        let mut fde = FrameDescriptionEntry {
7128            offset: 0,
7129            length: 0,
7130            format: Format::Dwarf32,
7131            cie: cie.clone(),
7132            initial_address: 0xfeed_face,
7133            address_range: 9000,
7134            augmentation: Some(AugmentationData::default()),
7135            instructions: EndianSlice::new(&instrs, LittleEndian),
7136        };
7137
7138        let rest = [1, 2, 3, 4];
7139
7140        let kind = eh_frame_le();
7141        let section = Section::with_endian(kind.endian())
7142            .fde(kind, cie_offset, &mut fde)
7143            .append_bytes(&rest)
7144            .get_contents()
7145            .unwrap();
7146        let section = kind.section(&section);
7147        let input = &mut section.section().clone();
7148
7149        let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7150        assert_eq!(result, Ok(fde));
7151        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7152    }
7153
7154    #[test]
7155    fn test_eh_frame_fde_lsda_augmentation() {
7156        let instrs = [1, 2, 3, 4];
7157        let cie_offset = 1;
7158
7159        let mut cie = make_test_cie();
7160        cie.format = Format::Dwarf32;
7161        cie.version = 1;
7162        cie.augmentation = Some(Augmentation::default());
7163        cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr);
7164
7165        let mut fde = FrameDescriptionEntry {
7166            offset: 0,
7167            length: 0,
7168            format: Format::Dwarf32,
7169            cie: cie.clone(),
7170            initial_address: 0xfeed_face,
7171            address_range: 9000,
7172            augmentation: Some(AugmentationData {
7173                lsda: Some(Pointer::Direct(0x1122_3344)),
7174            }),
7175            instructions: EndianSlice::new(&instrs, LittleEndian),
7176        };
7177
7178        let rest = [1, 2, 3, 4];
7179
7180        let kind = eh_frame_le();
7181        let section = Section::with_endian(kind.endian())
7182            .fde(kind, cie_offset, &mut fde)
7183            .append_bytes(&rest)
7184            .get_contents()
7185            .unwrap();
7186        let section = kind.section(&section);
7187        let input = &mut section.section().clone();
7188
7189        let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7190        assert_eq!(result, Ok(fde));
7191        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7192    }
7193
7194    #[test]
7195    fn test_eh_frame_fde_lsda_function_relative() {
7196        let instrs = [1, 2, 3, 4];
7197        let cie_offset = 1;
7198
7199        let mut cie = make_test_cie();
7200        cie.format = Format::Dwarf32;
7201        cie.version = 1;
7202        cie.augmentation = Some(Augmentation::default());
7203        cie.augmentation.as_mut().unwrap().lsda =
7204            Some(constants::DW_EH_PE_funcrel | constants::DW_EH_PE_absptr);
7205
7206        let mut fde = FrameDescriptionEntry {
7207            offset: 0,
7208            length: 0,
7209            format: Format::Dwarf32,
7210            cie: cie.clone(),
7211            initial_address: 0xfeed_face,
7212            address_range: 9000,
7213            augmentation: Some(AugmentationData {
7214                lsda: Some(Pointer::Direct(0xbeef)),
7215            }),
7216            instructions: EndianSlice::new(&instrs, LittleEndian),
7217        };
7218
7219        let rest = [1, 2, 3, 4];
7220
7221        let kind = eh_frame_le();
7222        let section = Section::with_endian(kind.endian())
7223            .append_repeated(10, 10)
7224            .fde(kind, cie_offset, &mut fde)
7225            .append_bytes(&rest)
7226            .get_contents()
7227            .unwrap();
7228        let section = kind.section(&section);
7229        let input = &mut section.section().range_from(10..);
7230
7231        // Adjust the FDE's augmentation to be relative to the function.
7232        fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef));
7233
7234        let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7235        assert_eq!(result, Ok(fde));
7236        assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7237    }
7238
7239    #[test]
7240    fn test_eh_frame_cie_personality_function_relative_bad_context() {
7241        let instrs = [1, 2, 3, 4];
7242
7243        let length = Label::new();
7244        let start = Label::new();
7245        let end = Label::new();
7246
7247        let aug_len = Label::new();
7248        let aug_start = Label::new();
7249        let aug_end = Label::new();
7250
7251        let section = Section::with_endian(Endian::Little)
7252            // Length
7253            .L32(&length)
7254            .mark(&start)
7255            // CIE ID
7256            .L32(0)
7257            // Version
7258            .D8(1)
7259            // Augmentation
7260            .append_bytes(b"zP\0")
7261            // Code alignment factor
7262            .uleb(1)
7263            // Data alignment factor
7264            .sleb(1)
7265            // Return address register
7266            .uleb(1)
7267            // Augmentation data length. This is a uleb, be we rely on the value
7268            // being less than 2^7 and therefore a valid uleb (can't use Label
7269            // with uleb).
7270            .D8(&aug_len)
7271            .mark(&aug_start)
7272            // Augmentation data. Personality encoding and then encoded pointer.
7273            .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0)
7274            .uleb(1)
7275            .mark(&aug_end)
7276            // Initial instructions
7277            .append_bytes(&instrs)
7278            .mark(&end);
7279
7280        length.set_const((&end - &start) as u64);
7281        aug_len.set_const((&aug_end - &aug_start) as u64);
7282
7283        let section = section.get_contents().unwrap();
7284        let section = EhFrame::new(&section, LittleEndian);
7285
7286        let bases = BaseAddresses::default();
7287        let mut iter = section.entries(&bases);
7288        assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext));
7289    }
7290
7291    #[test]
7292    fn register_rule_map_eq() {
7293        // Different order, but still equal.
7294        let map1: RegisterRuleMap<usize> = [
7295            (Register(0), RegisterRule::SameValue),
7296            (Register(3), RegisterRule::Offset(1)),
7297        ]
7298        .iter()
7299        .collect();
7300        let map2: RegisterRuleMap<usize> = [
7301            (Register(3), RegisterRule::Offset(1)),
7302            (Register(0), RegisterRule::SameValue),
7303        ]
7304        .iter()
7305        .collect();
7306        assert_eq!(map1, map2);
7307        assert_eq!(map2, map1);
7308
7309        // Not equal.
7310        let map3: RegisterRuleMap<usize> = [
7311            (Register(0), RegisterRule::SameValue),
7312            (Register(2), RegisterRule::Offset(1)),
7313        ]
7314        .iter()
7315        .collect();
7316        let map4: RegisterRuleMap<usize> = [
7317            (Register(3), RegisterRule::Offset(1)),
7318            (Register(0), RegisterRule::SameValue),
7319        ]
7320        .iter()
7321        .collect();
7322        assert!(map3 != map4);
7323        assert!(map4 != map3);
7324
7325        // One has undefined explicitly set, other implicitly has undefined.
7326        let mut map5 = RegisterRuleMap::<usize>::default();
7327        map5.set(Register(0), RegisterRule::SameValue).unwrap();
7328        map5.set(Register(0), RegisterRule::Undefined).unwrap();
7329        let map6 = RegisterRuleMap::<usize>::default();
7330        assert_eq!(map5, map6);
7331        assert_eq!(map6, map5);
7332    }
7333
7334    #[test]
7335    fn iter_register_rules() {
7336        let row = UnwindTableRow::<usize> {
7337            registers: [
7338                (Register(0), RegisterRule::SameValue),
7339                (Register(1), RegisterRule::Offset(1)),
7340                (Register(2), RegisterRule::ValOffset(2)),
7341            ]
7342            .iter()
7343            .collect(),
7344            ..Default::default()
7345        };
7346
7347        let mut found0 = false;
7348        let mut found1 = false;
7349        let mut found2 = false;
7350
7351        for &(register, ref rule) in row.registers() {
7352            match register.0 {
7353                0 => {
7354                    assert!(!found0);
7355                    found0 = true;
7356                    assert_eq!(*rule, RegisterRule::SameValue);
7357                }
7358                1 => {
7359                    assert!(!found1);
7360                    found1 = true;
7361                    assert_eq!(*rule, RegisterRule::Offset(1));
7362                }
7363                2 => {
7364                    assert!(!found2);
7365                    found2 = true;
7366                    assert_eq!(*rule, RegisterRule::ValOffset(2));
7367                }
7368                x => panic!("Unexpected register rule: ({}, {:?})", x, rule),
7369            }
7370        }
7371
7372        assert!(found0);
7373        assert!(found1);
7374        assert!(found2);
7375    }
7376
7377    #[test]
7378    #[cfg(target_pointer_width = "64")]
7379    fn size_of_unwind_ctx() {
7380        use core::mem;
7381        let size = mem::size_of::<UnwindContext<usize>>();
7382        let max_size = 30968;
7383        if size > max_size {
7384            assert_eq!(size, max_size);
7385        }
7386    }
7387
7388    #[test]
7389    #[cfg(target_pointer_width = "64")]
7390    fn size_of_register_rule_map() {
7391        use core::mem;
7392        let size = mem::size_of::<RegisterRuleMap<usize>>();
7393        let max_size = 6152;
7394        if size > max_size {
7395            assert_eq!(size, max_size);
7396        }
7397    }
7398
7399    #[test]
7400    fn test_parse_pointer_encoding_ok() {
7401        use crate::endianity::NativeEndian;
7402        let expected = constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_pcrel;
7403        let input = [expected.0, 1, 2, 3, 4];
7404        let input = &mut EndianSlice::new(&input, NativeEndian);
7405        assert_eq!(parse_pointer_encoding(input), Ok(expected));
7406        assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian));
7407    }
7408
7409    #[test]
7410    fn test_parse_pointer_encoding_bad_encoding() {
7411        use crate::endianity::NativeEndian;
7412        let expected =
7413            constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0);
7414        let input = [expected.0, 1, 2, 3, 4];
7415        let input = &mut EndianSlice::new(&input, NativeEndian);
7416        assert_eq!(
7417            Err(Error::UnknownPointerEncoding(expected)),
7418            parse_pointer_encoding(input)
7419        );
7420    }
7421
7422    #[test]
7423    fn test_parse_encoded_pointer_absptr() {
7424        let encoding = constants::DW_EH_PE_absptr;
7425        let expected_rest = [1, 2, 3, 4];
7426
7427        let input = Section::with_endian(Endian::Little)
7428            .L32(0xf00d_f00d)
7429            .append_bytes(&expected_rest);
7430        let input = input.get_contents().unwrap();
7431        let input = EndianSlice::new(&input, LittleEndian);
7432        let mut rest = input;
7433
7434        let parameters = PointerEncodingParameters {
7435            bases: &SectionBaseAddresses::default(),
7436            func_base: None,
7437            address_size: 4,
7438            section: &input,
7439        };
7440        assert_eq!(
7441            parse_encoded_pointer(encoding, &parameters, &mut rest),
7442            Ok(Pointer::Direct(0xf00d_f00d))
7443        );
7444        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7445    }
7446
7447    #[test]
7448    fn test_parse_encoded_pointer_pcrel() {
7449        let encoding = constants::DW_EH_PE_pcrel;
7450        let expected_rest = [1, 2, 3, 4];
7451
7452        let input = Section::with_endian(Endian::Little)
7453            .append_repeated(0, 0x10)
7454            .L32(0x1)
7455            .append_bytes(&expected_rest);
7456        let input = input.get_contents().unwrap();
7457        let input = EndianSlice::new(&input, LittleEndian);
7458        let mut rest = input.range_from(0x10..);
7459
7460        let parameters = PointerEncodingParameters {
7461            bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame,
7462            func_base: None,
7463            address_size: 4,
7464            section: &input,
7465        };
7466        assert_eq!(
7467            parse_encoded_pointer(encoding, &parameters, &mut rest),
7468            Ok(Pointer::Direct(0x111))
7469        );
7470        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7471    }
7472
7473    #[test]
7474    fn test_parse_encoded_pointer_pcrel_undefined() {
7475        let encoding = constants::DW_EH_PE_pcrel;
7476
7477        let input = Section::with_endian(Endian::Little).L32(0x1);
7478        let input = input.get_contents().unwrap();
7479        let input = EndianSlice::new(&input, LittleEndian);
7480        let mut rest = input;
7481
7482        let parameters = PointerEncodingParameters {
7483            bases: &SectionBaseAddresses::default(),
7484            func_base: None,
7485            address_size: 4,
7486            section: &input,
7487        };
7488        assert_eq!(
7489            parse_encoded_pointer(encoding, &parameters, &mut rest),
7490            Err(Error::PcRelativePointerButSectionBaseIsUndefined)
7491        );
7492    }
7493
7494    #[test]
7495    fn test_parse_encoded_pointer_textrel() {
7496        let encoding = constants::DW_EH_PE_textrel;
7497        let expected_rest = [1, 2, 3, 4];
7498
7499        let input = Section::with_endian(Endian::Little)
7500            .L32(0x1)
7501            .append_bytes(&expected_rest);
7502        let input = input.get_contents().unwrap();
7503        let input = EndianSlice::new(&input, LittleEndian);
7504        let mut rest = input;
7505
7506        let parameters = PointerEncodingParameters {
7507            bases: &BaseAddresses::default().set_text(0x10).eh_frame,
7508            func_base: None,
7509            address_size: 4,
7510            section: &input,
7511        };
7512        assert_eq!(
7513            parse_encoded_pointer(encoding, &parameters, &mut rest),
7514            Ok(Pointer::Direct(0x11))
7515        );
7516        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7517    }
7518
7519    #[test]
7520    fn test_parse_encoded_pointer_textrel_undefined() {
7521        let encoding = constants::DW_EH_PE_textrel;
7522
7523        let input = Section::with_endian(Endian::Little).L32(0x1);
7524        let input = input.get_contents().unwrap();
7525        let input = EndianSlice::new(&input, LittleEndian);
7526        let mut rest = input;
7527
7528        let parameters = PointerEncodingParameters {
7529            bases: &SectionBaseAddresses::default(),
7530            func_base: None,
7531            address_size: 4,
7532            section: &input,
7533        };
7534        assert_eq!(
7535            parse_encoded_pointer(encoding, &parameters, &mut rest),
7536            Err(Error::TextRelativePointerButTextBaseIsUndefined)
7537        );
7538    }
7539
7540    #[test]
7541    fn test_parse_encoded_pointer_datarel() {
7542        let encoding = constants::DW_EH_PE_datarel;
7543        let expected_rest = [1, 2, 3, 4];
7544
7545        let input = Section::with_endian(Endian::Little)
7546            .L32(0x1)
7547            .append_bytes(&expected_rest);
7548        let input = input.get_contents().unwrap();
7549        let input = EndianSlice::new(&input, LittleEndian);
7550        let mut rest = input;
7551
7552        let parameters = PointerEncodingParameters {
7553            bases: &BaseAddresses::default().set_got(0x10).eh_frame,
7554            func_base: None,
7555            address_size: 4,
7556            section: &input,
7557        };
7558        assert_eq!(
7559            parse_encoded_pointer(encoding, &parameters, &mut rest),
7560            Ok(Pointer::Direct(0x11))
7561        );
7562        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7563    }
7564
7565    #[test]
7566    fn test_parse_encoded_pointer_datarel_undefined() {
7567        let encoding = constants::DW_EH_PE_datarel;
7568
7569        let input = Section::with_endian(Endian::Little).L32(0x1);
7570        let input = input.get_contents().unwrap();
7571        let input = EndianSlice::new(&input, LittleEndian);
7572        let mut rest = input;
7573
7574        let parameters = PointerEncodingParameters {
7575            bases: &SectionBaseAddresses::default(),
7576            func_base: None,
7577            address_size: 4,
7578            section: &input,
7579        };
7580        assert_eq!(
7581            parse_encoded_pointer(encoding, &parameters, &mut rest),
7582            Err(Error::DataRelativePointerButDataBaseIsUndefined)
7583        );
7584    }
7585
7586    #[test]
7587    fn test_parse_encoded_pointer_funcrel() {
7588        let encoding = constants::DW_EH_PE_funcrel;
7589        let expected_rest = [1, 2, 3, 4];
7590
7591        let input = Section::with_endian(Endian::Little)
7592            .L32(0x1)
7593            .append_bytes(&expected_rest);
7594        let input = input.get_contents().unwrap();
7595        let input = EndianSlice::new(&input, LittleEndian);
7596        let mut rest = input;
7597
7598        let parameters = PointerEncodingParameters {
7599            bases: &SectionBaseAddresses::default(),
7600            func_base: Some(0x10),
7601            address_size: 4,
7602            section: &input,
7603        };
7604        assert_eq!(
7605            parse_encoded_pointer(encoding, &parameters, &mut rest),
7606            Ok(Pointer::Direct(0x11))
7607        );
7608        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7609    }
7610
7611    #[test]
7612    fn test_parse_encoded_pointer_funcrel_undefined() {
7613        let encoding = constants::DW_EH_PE_funcrel;
7614
7615        let input = Section::with_endian(Endian::Little).L32(0x1);
7616        let input = input.get_contents().unwrap();
7617        let input = EndianSlice::new(&input, LittleEndian);
7618        let mut rest = input;
7619
7620        let parameters = PointerEncodingParameters {
7621            bases: &SectionBaseAddresses::default(),
7622            func_base: None,
7623            address_size: 4,
7624            section: &input,
7625        };
7626        assert_eq!(
7627            parse_encoded_pointer(encoding, &parameters, &mut rest),
7628            Err(Error::FuncRelativePointerInBadContext)
7629        );
7630    }
7631
7632    #[test]
7633    fn test_parse_encoded_pointer_uleb128() {
7634        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_uleb128;
7635        let expected_rest = [1, 2, 3, 4];
7636
7637        let input = Section::with_endian(Endian::Little)
7638            .uleb(0x12_3456)
7639            .append_bytes(&expected_rest);
7640        let input = input.get_contents().unwrap();
7641        let input = EndianSlice::new(&input, LittleEndian);
7642        let mut rest = input;
7643
7644        let parameters = PointerEncodingParameters {
7645            bases: &SectionBaseAddresses::default(),
7646            func_base: None,
7647            address_size: 4,
7648            section: &input,
7649        };
7650        assert_eq!(
7651            parse_encoded_pointer(encoding, &parameters, &mut rest),
7652            Ok(Pointer::Direct(0x12_3456))
7653        );
7654        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7655    }
7656
7657    #[test]
7658    fn test_parse_encoded_pointer_udata2() {
7659        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata2;
7660        let expected_rest = [1, 2, 3, 4];
7661
7662        let input = Section::with_endian(Endian::Little)
7663            .L16(0x1234)
7664            .append_bytes(&expected_rest);
7665        let input = input.get_contents().unwrap();
7666        let input = EndianSlice::new(&input, LittleEndian);
7667        let mut rest = input;
7668
7669        let parameters = PointerEncodingParameters {
7670            bases: &SectionBaseAddresses::default(),
7671            func_base: None,
7672            address_size: 4,
7673            section: &input,
7674        };
7675        assert_eq!(
7676            parse_encoded_pointer(encoding, &parameters, &mut rest),
7677            Ok(Pointer::Direct(0x1234))
7678        );
7679        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7680    }
7681
7682    #[test]
7683    fn test_parse_encoded_pointer_udata4() {
7684        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata4;
7685        let expected_rest = [1, 2, 3, 4];
7686
7687        let input = Section::with_endian(Endian::Little)
7688            .L32(0x1234_5678)
7689            .append_bytes(&expected_rest);
7690        let input = input.get_contents().unwrap();
7691        let input = EndianSlice::new(&input, LittleEndian);
7692        let mut rest = input;
7693
7694        let parameters = PointerEncodingParameters {
7695            bases: &SectionBaseAddresses::default(),
7696            func_base: None,
7697            address_size: 4,
7698            section: &input,
7699        };
7700        assert_eq!(
7701            parse_encoded_pointer(encoding, &parameters, &mut rest),
7702            Ok(Pointer::Direct(0x1234_5678))
7703        );
7704        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7705    }
7706
7707    #[test]
7708    fn test_parse_encoded_pointer_udata8() {
7709        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata8;
7710        let expected_rest = [1, 2, 3, 4];
7711
7712        let input = Section::with_endian(Endian::Little)
7713            .L64(0x1234_5678_1234_5678)
7714            .append_bytes(&expected_rest);
7715        let input = input.get_contents().unwrap();
7716        let input = EndianSlice::new(&input, LittleEndian);
7717        let mut rest = input;
7718
7719        let parameters = PointerEncodingParameters {
7720            bases: &SectionBaseAddresses::default(),
7721            func_base: None,
7722            address_size: 8,
7723            section: &input,
7724        };
7725        assert_eq!(
7726            parse_encoded_pointer(encoding, &parameters, &mut rest),
7727            Ok(Pointer::Direct(0x1234_5678_1234_5678))
7728        );
7729        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7730    }
7731
7732    #[test]
7733    fn test_parse_encoded_pointer_sleb128() {
7734        let encoding = constants::DW_EH_PE_textrel | constants::DW_EH_PE_sleb128;
7735        let expected_rest = [1, 2, 3, 4];
7736
7737        let input = Section::with_endian(Endian::Little)
7738            .sleb(-0x1111)
7739            .append_bytes(&expected_rest);
7740        let input = input.get_contents().unwrap();
7741        let input = EndianSlice::new(&input, LittleEndian);
7742        let mut rest = input;
7743
7744        let parameters = PointerEncodingParameters {
7745            bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame,
7746            func_base: None,
7747            address_size: 4,
7748            section: &input,
7749        };
7750        assert_eq!(
7751            parse_encoded_pointer(encoding, &parameters, &mut rest),
7752            Ok(Pointer::Direct(0x1111_0000))
7753        );
7754        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7755    }
7756
7757    #[test]
7758    fn test_parse_encoded_pointer_sdata2() {
7759        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata2;
7760        let expected_rest = [1, 2, 3, 4];
7761        let expected = 0x111_i16;
7762
7763        let input = Section::with_endian(Endian::Little)
7764            .L16(expected as u16)
7765            .append_bytes(&expected_rest);
7766        let input = input.get_contents().unwrap();
7767        let input = EndianSlice::new(&input, LittleEndian);
7768        let mut rest = input;
7769
7770        let parameters = PointerEncodingParameters {
7771            bases: &SectionBaseAddresses::default(),
7772            func_base: None,
7773            address_size: 4,
7774            section: &input,
7775        };
7776        assert_eq!(
7777            parse_encoded_pointer(encoding, &parameters, &mut rest),
7778            Ok(Pointer::Direct(expected as u64))
7779        );
7780        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7781    }
7782
7783    #[test]
7784    fn test_parse_encoded_pointer_sdata4() {
7785        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata4;
7786        let expected_rest = [1, 2, 3, 4];
7787        let expected = 0x111_1111_i32;
7788
7789        let input = Section::with_endian(Endian::Little)
7790            .L32(expected as u32)
7791            .append_bytes(&expected_rest);
7792        let input = input.get_contents().unwrap();
7793        let input = EndianSlice::new(&input, LittleEndian);
7794        let mut rest = input;
7795
7796        let parameters = PointerEncodingParameters {
7797            bases: &SectionBaseAddresses::default(),
7798            func_base: None,
7799            address_size: 4,
7800            section: &input,
7801        };
7802        assert_eq!(
7803            parse_encoded_pointer(encoding, &parameters, &mut rest),
7804            Ok(Pointer::Direct(expected as u64))
7805        );
7806        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7807    }
7808
7809    #[test]
7810    fn test_parse_encoded_pointer_sdata8() {
7811        let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata8;
7812        let expected_rest = [1, 2, 3, 4];
7813        let expected = -0x11_1111_1222_2222_i64;
7814
7815        let input = Section::with_endian(Endian::Little)
7816            .L64(expected as u64)
7817            .append_bytes(&expected_rest);
7818        let input = input.get_contents().unwrap();
7819        let input = EndianSlice::new(&input, LittleEndian);
7820        let mut rest = input;
7821
7822        let parameters = PointerEncodingParameters {
7823            bases: &SectionBaseAddresses::default(),
7824            func_base: None,
7825            address_size: 8,
7826            section: &input,
7827        };
7828        assert_eq!(
7829            parse_encoded_pointer(encoding, &parameters, &mut rest),
7830            Ok(Pointer::Direct(expected as u64))
7831        );
7832        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7833    }
7834
7835    #[test]
7836    fn test_parse_encoded_pointer_omit() {
7837        let encoding = constants::DW_EH_PE_omit;
7838
7839        let input = Section::with_endian(Endian::Little).L32(0x1);
7840        let input = input.get_contents().unwrap();
7841        let input = EndianSlice::new(&input, LittleEndian);
7842        let mut rest = input;
7843
7844        let parameters = PointerEncodingParameters {
7845            bases: &SectionBaseAddresses::default(),
7846            func_base: None,
7847            address_size: 4,
7848            section: &input,
7849        };
7850        assert_eq!(
7851            parse_encoded_pointer(encoding, &parameters, &mut rest),
7852            Err(Error::CannotParseOmitPointerEncoding)
7853        );
7854        assert_eq!(rest, input);
7855    }
7856
7857    #[test]
7858    fn test_parse_encoded_pointer_bad_encoding() {
7859        let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1);
7860
7861        let input = Section::with_endian(Endian::Little).L32(0x1);
7862        let input = input.get_contents().unwrap();
7863        let input = EndianSlice::new(&input, LittleEndian);
7864        let mut rest = input;
7865
7866        let parameters = PointerEncodingParameters {
7867            bases: &SectionBaseAddresses::default(),
7868            func_base: None,
7869            address_size: 4,
7870            section: &input,
7871        };
7872        assert_eq!(
7873            parse_encoded_pointer(encoding, &parameters, &mut rest),
7874            Err(Error::UnknownPointerEncoding(encoding))
7875        );
7876    }
7877
7878    #[test]
7879    fn test_parse_encoded_pointer_aligned() {
7880        // FIXME: support this encoding!
7881
7882        let encoding = constants::DW_EH_PE_aligned;
7883
7884        let input = Section::with_endian(Endian::Little).L32(0x1);
7885        let input = input.get_contents().unwrap();
7886        let input = EndianSlice::new(&input, LittleEndian);
7887        let mut rest = input;
7888
7889        let parameters = PointerEncodingParameters {
7890            bases: &SectionBaseAddresses::default(),
7891            func_base: None,
7892            address_size: 4,
7893            section: &input,
7894        };
7895        assert_eq!(
7896            parse_encoded_pointer(encoding, &parameters, &mut rest),
7897            Err(Error::UnsupportedPointerEncoding)
7898        );
7899    }
7900
7901    #[test]
7902    fn test_parse_encoded_pointer_indirect() {
7903        let expected_rest = [1, 2, 3, 4];
7904        let encoding = constants::DW_EH_PE_indirect;
7905
7906        let input = Section::with_endian(Endian::Little)
7907            .L32(0x1234_5678)
7908            .append_bytes(&expected_rest);
7909        let input = input.get_contents().unwrap();
7910        let input = EndianSlice::new(&input, LittleEndian);
7911        let mut rest = input;
7912
7913        let parameters = PointerEncodingParameters {
7914            bases: &SectionBaseAddresses::default(),
7915            func_base: None,
7916            address_size: 4,
7917            section: &input,
7918        };
7919        assert_eq!(
7920            parse_encoded_pointer(encoding, &parameters, &mut rest),
7921            Ok(Pointer::Indirect(0x1234_5678))
7922        );
7923        assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7924    }
7925
7926    #[test]
7927    fn test_unwind_context_reuse() {
7928        fn unwind_one(ctx: &mut UnwindContext<usize>, data: &[u8]) {
7929            let debug_frame = DebugFrame::new(data, NativeEndian);
7930            let bases = Default::default();
7931            let result = debug_frame.unwind_info_for_address(
7932                &bases,
7933                ctx,
7934                0xbadb_ad99,
7935                DebugFrame::cie_from_offset,
7936            );
7937            assert!(result.is_err());
7938            assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
7939        }
7940
7941        // Use the same context for two different data lifetimes.
7942        let mut ctx: UnwindContext<usize> = UnwindContext::new();
7943        {
7944            let data1 = vec![];
7945            unwind_one(&mut ctx, &data1);
7946        }
7947        {
7948            let data2 = vec![];
7949            unwind_one(&mut ctx, &data2);
7950        }
7951    }
7952}