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