Skip to main content

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