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