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