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