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