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