1#[cfg(feature = "read")]
2use alloc::boxed::Box;
3
4use core::cmp::Ordering;
5use core::fmt::{self, Debug};
6use core::iter::FromIterator;
7use core::mem;
8use core::num::Wrapping;
9
10use super::util::{ArrayLike, ArrayVec};
11use crate::common::{
12 DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor,
13};
14use crate::constants::{self, DwEhPe};
15use crate::endianity::Endianity;
16use crate::read::{
17 EndianSlice, Error, Expression, Reader, ReaderAddress, ReaderOffset, Result, Section,
18 StoreOnHeap,
19};
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct DebugFrame<R: Reader> {
37 section: R,
38 address_size: u8,
39 vendor: Vendor,
40}
41
42impl<R: Reader> DebugFrame<R> {
43 pub fn set_address_size(&mut self, address_size: u8) {
48 self.address_size = address_size
49 }
50
51 pub fn set_vendor(&mut self, vendor: Vendor) {
55 self.vendor = vendor;
56 }
57}
58
59impl<'input, Endian> DebugFrame<EndianSlice<'input, Endian>>
60where
61 Endian: Endianity,
62{
63 pub fn new(section: &'input [u8], endian: Endian) -> Self {
79 Self::from(EndianSlice::new(section, endian))
80 }
81}
82
83impl<R: Reader> Section<R> for DebugFrame<R> {
84 fn id() -> SectionId {
85 SectionId::DebugFrame
86 }
87
88 fn reader(&self) -> &R {
89 &self.section
90 }
91}
92
93impl<R: Reader> From<R> for DebugFrame<R> {
94 fn from(section: R) -> Self {
95 DebugFrame {
97 section,
98 address_size: mem::size_of::<usize>() as u8,
99 vendor: Vendor::Default,
100 }
101 }
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109pub struct EhFrameHdr<R: Reader>(R);
110
111#[derive(Clone, Debug)]
113pub struct ParsedEhFrameHdr<R: Reader> {
114 address_size: u8,
115 section: R,
116
117 eh_frame_ptr: Pointer,
118 fde_count: u64,
119 table_enc: DwEhPe,
120 table: R,
121}
122
123impl<'input, Endian> EhFrameHdr<EndianSlice<'input, Endian>>
124where
125 Endian: Endianity,
126{
127 pub fn new(section: &'input [u8], endian: Endian) -> Self {
129 Self::from(EndianSlice::new(section, endian))
130 }
131}
132
133impl<R: Reader> EhFrameHdr<R> {
134 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 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
181impl<R: Reader> Section<R> for EhFrameHdr<R> {
182 fn id() -> SectionId {
183 SectionId::EhFrameHdr
184 }
185
186 fn reader(&self) -> &R {
187 &self.0
188 }
189}
190
191impl<R: Reader> From<R> for EhFrameHdr<R> {
192 fn from(section: R) -> Self {
193 EhFrameHdr(section)
194 }
195}
196
197impl<R: Reader> ParsedEhFrameHdr<R> {
198 pub fn eh_frame_ptr(&self) -> Pointer {
200 self.eh_frame_ptr
201 }
202
203 pub fn table(&self) -> Option<EhHdrTable<'_, R>> {
205 if self.fde_count == 0 {
215 None
216 } else {
217 Some(EhHdrTable { hdr: self })
218 }
219 }
220}
221
222#[derive(Debug)]
229pub struct EhHdrTableIter<'a, 'bases, R: Reader> {
230 hdr: &'a ParsedEhFrameHdr<R>,
231 table: R,
232 bases: &'bases BaseAddresses,
233 remain: u64,
234}
235
236impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> {
237 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 pub fn nth(&mut self, n: usize) -> Result<Option<(Pointer, Pointer)>> {
257 use core::convert::TryFrom;
258 let size = match self.hdr.table_enc.format() {
259 constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
260 return Err(Error::VariableLengthSearchTable);
261 }
262 constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
263 constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
264 constants::DW_EH_PE_sdata8 | constants::DW_EH_PE_udata8 => 8,
265 _ => return Err(Error::UnknownPointerEncoding(self.hdr.table_enc)),
266 };
267
268 let row_size = size * 2;
269 let n = u64::try_from(n).map_err(|_| Error::UnsupportedOffset)?;
270 self.remain = self.remain.saturating_sub(n);
271 self.table.skip(R::Offset::from_u64(n * row_size)?)?;
272 self.next()
273 }
274}
275
276#[cfg(feature = "fallible-iterator")]
277impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> {
278 type Item = (Pointer, Pointer);
279 type Error = Error;
280 fn next(&mut self) -> Result<Option<Self::Item>> {
281 EhHdrTableIter::next(self)
282 }
283
284 fn size_hint(&self) -> (usize, Option<usize>) {
285 use core::convert::TryInto;
286 (
287 self.remain.try_into().unwrap_or(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#[derive(Debug, Clone)]
299pub struct EhHdrTable<'a, R: Reader> {
300 hdr: &'a ParsedEhFrameHdr<R>,
301}
302
303impl<'a, R: Reader + 'a> EhHdrTable<'a, R> {
304 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 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 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 R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset)
385 }
386
387 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 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
488pub struct EhFrame<R: Reader> {
489 section: R,
490 address_size: u8,
491 vendor: Vendor,
492}
493
494impl<R: Reader> EhFrame<R> {
495 pub fn set_address_size(&mut self, address_size: u8) {
499 self.address_size = address_size
500 }
501
502 pub fn set_vendor(&mut self, vendor: Vendor) {
506 self.vendor = vendor;
507 }
508}
509
510impl<'input, Endian> EhFrame<EndianSlice<'input, Endian>>
511where
512 Endian: Endianity,
513{
514 pub fn new(section: &'input [u8], endian: Endian) -> Self {
530 Self::from(EndianSlice::new(section, endian))
531 }
532}
533
534impl<R: Reader> Section<R> for EhFrame<R> {
535 fn id() -> SectionId {
536 SectionId::EhFrame
537 }
538
539 fn reader(&self) -> &R {
540 &self.section
541 }
542}
543
544impl<R: Reader> From<R> for EhFrame<R> {
545 fn from(section: R) -> Self {
546 EhFrame {
548 section,
549 address_size: mem::size_of::<usize>() as u8,
550 vendor: Vendor::Default,
551 }
552 }
553}
554
555#[doc(hidden)]
558#[allow(missing_docs)]
559#[derive(Clone, Copy, Debug, PartialEq, Eq)]
560pub enum CieOffsetEncoding {
561 U32,
562 U64,
563}
564
565pub trait UnwindOffset<T = usize>: Copy + Debug + Eq + From<T>
569where
570 T: ReaderOffset,
571{
572 fn into(self) -> T;
574}
575
576impl<T> UnwindOffset<T> for DebugFrameOffset<T>
577where
578 T: ReaderOffset,
579{
580 #[inline]
581 fn into(self) -> T {
582 self.0
583 }
584}
585
586impl<T> UnwindOffset<T> for EhFrameOffset<T>
587where
588 T: ReaderOffset,
589{
590 #[inline]
591 fn into(self) -> T {
592 self.0
593 }
594}
595
596#[doc(hidden)]
600pub trait _UnwindSectionPrivate<R: Reader> {
601 fn section(&self) -> &R;
603
604 fn length_value_is_end_of_entries(length: R::Offset) -> bool;
607
608 fn is_cie(format: Format, id: u64) -> bool;
610
611 fn cie_offset_encoding(format: Format) -> CieOffsetEncoding;
614
615 fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset>;
621
622 fn has_address_and_segment_sizes(version: u8) -> bool;
625
626 fn address_size(&self) -> u8;
628
629 fn vendor(&self) -> Vendor;
631}
632
633pub trait UnwindSection<R: Reader>: Clone + Debug + _UnwindSectionPrivate<R> {
637 type Offset: UnwindOffset<R::Offset>;
640
641 fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> {
647 CfiEntriesIter {
648 section: self.clone(),
649 bases,
650 input: self.section().clone(),
651 }
652 }
653
654 fn cie_from_offset(
656 &self,
657 bases: &BaseAddresses,
658 offset: Self::Offset,
659 ) -> Result<CommonInformationEntry<R>> {
660 let offset = UnwindOffset::into(offset);
661 let input = &mut self.section().clone();
662 input.skip(offset)?;
663 CommonInformationEntry::parse(bases, self, input)
664 }
665
666 fn partial_fde_from_offset<'bases>(
668 &self,
669 bases: &'bases BaseAddresses,
670 offset: Self::Offset,
671 ) -> Result<PartialFrameDescriptionEntry<'bases, Self, R>> {
672 let offset = UnwindOffset::into(offset);
673 let input = &mut self.section().clone();
674 input.skip(offset)?;
675 PartialFrameDescriptionEntry::parse_partial(self, bases, input)
676 }
677
678 fn fde_from_offset<F>(
680 &self,
681 bases: &BaseAddresses,
682 offset: Self::Offset,
683 get_cie: F,
684 ) -> Result<FrameDescriptionEntry<R>>
685 where
686 F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
687 {
688 let partial = self.partial_fde_from_offset(bases, offset)?;
689 partial.parse(get_cie)
690 }
691
692 fn fde_for_address<F>(
704 &self,
705 bases: &BaseAddresses,
706 address: u64,
707 mut get_cie: F,
708 ) -> Result<FrameDescriptionEntry<R>>
709 where
710 F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
711 {
712 let mut entries = self.entries(bases);
713 while let Some(entry) = entries.next()? {
714 match entry {
715 CieOrFde::Cie(_) => {}
716 CieOrFde::Fde(partial) => {
717 let fde = partial.parse(&mut get_cie)?;
718 if fde.contains(address) {
719 return Ok(fde);
720 }
721 }
722 }
723 }
724 Err(Error::NoUnwindInfoForAddress)
725 }
726
727 #[inline]
773 fn unwind_info_for_address<'ctx, F, S>(
774 &self,
775 bases: &BaseAddresses,
776 ctx: &'ctx mut UnwindContext<R::Offset, S>,
777 address: u64,
778 get_cie: F,
779 ) -> Result<&'ctx UnwindTableRow<R::Offset, S>>
780 where
781 F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result<CommonInformationEntry<R>>,
782 S: UnwindContextStorage<R::Offset>,
783 {
784 let fde = self.fde_for_address(bases, address, get_cie)?;
785 fde.unwind_info_for_address(self, bases, ctx, address)
786 }
787}
788
789impl<R: Reader> _UnwindSectionPrivate<R> for DebugFrame<R> {
790 fn section(&self) -> &R {
791 &self.section
792 }
793
794 fn length_value_is_end_of_entries(_: R::Offset) -> bool {
795 false
796 }
797
798 fn is_cie(format: Format, id: u64) -> bool {
799 match format {
800 Format::Dwarf32 => id == 0xffff_ffff,
801 Format::Dwarf64 => id == 0xffff_ffff_ffff_ffff,
802 }
803 }
804
805 fn cie_offset_encoding(format: Format) -> CieOffsetEncoding {
806 match format {
807 Format::Dwarf32 => CieOffsetEncoding::U32,
808 Format::Dwarf64 => CieOffsetEncoding::U64,
809 }
810 }
811
812 fn resolve_cie_offset(&self, _: R::Offset, offset: R::Offset) -> Option<R::Offset> {
813 Some(offset)
814 }
815
816 fn has_address_and_segment_sizes(version: u8) -> bool {
817 version == 4
818 }
819
820 fn address_size(&self) -> u8 {
821 self.address_size
822 }
823
824 fn vendor(&self) -> Vendor {
825 self.vendor
826 }
827}
828
829impl<R: Reader> UnwindSection<R> for DebugFrame<R> {
830 type Offset = DebugFrameOffset<R::Offset>;
831}
832
833impl<R: Reader> _UnwindSectionPrivate<R> for EhFrame<R> {
834 fn section(&self) -> &R {
835 &self.section
836 }
837
838 fn length_value_is_end_of_entries(length: R::Offset) -> bool {
839 length.into_u64() == 0
840 }
841
842 fn is_cie(_: Format, id: u64) -> bool {
843 id == 0
844 }
845
846 fn cie_offset_encoding(_format: Format) -> CieOffsetEncoding {
847 CieOffsetEncoding::U32
850 }
851
852 fn resolve_cie_offset(&self, base: R::Offset, offset: R::Offset) -> Option<R::Offset> {
853 base.checked_sub(offset)
854 }
855
856 fn has_address_and_segment_sizes(_version: u8) -> bool {
857 false
858 }
859
860 fn address_size(&self) -> u8 {
861 self.address_size
862 }
863
864 fn vendor(&self) -> Vendor {
865 self.vendor
866 }
867}
868
869impl<R: Reader> UnwindSection<R> for EhFrame<R> {
870 type Offset = EhFrameOffset<R::Offset>;
871}
872
873#[derive(Clone, Default, Debug, PartialEq, Eq)]
896pub struct BaseAddresses {
897 pub eh_frame_hdr: SectionBaseAddresses,
899
900 pub eh_frame: SectionBaseAddresses,
902}
903
904#[derive(Clone, Default, Debug, PartialEq, Eq)]
909pub struct SectionBaseAddresses {
910 pub section: Option<u64>,
912
913 pub text: Option<u64>,
916
917 pub data: Option<u64>,
925}
926
927impl BaseAddresses {
928 #[inline]
930 pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self {
931 self.eh_frame_hdr.section = Some(addr);
932 self.eh_frame_hdr.data = Some(addr);
933 self
934 }
935
936 #[inline]
938 pub fn set_eh_frame(mut self, addr: u64) -> Self {
939 self.eh_frame.section = Some(addr);
940 self
941 }
942
943 #[inline]
945 pub fn set_text(mut self, addr: u64) -> Self {
946 self.eh_frame_hdr.text = Some(addr);
947 self.eh_frame.text = Some(addr);
948 self
949 }
950
951 #[inline]
953 pub fn set_got(mut self, addr: u64) -> Self {
954 self.eh_frame.data = Some(addr);
955 self
956 }
957}
958
959#[derive(Clone, Debug)]
999pub struct CfiEntriesIter<'bases, Section, R>
1000where
1001 R: Reader,
1002 Section: UnwindSection<R>,
1003{
1004 section: Section,
1005 bases: &'bases BaseAddresses,
1006 input: R,
1007}
1008
1009impl<'bases, Section, R> CfiEntriesIter<'bases, Section, R>
1010where
1011 R: Reader,
1012 Section: UnwindSection<R>,
1013{
1014 pub fn next(&mut self) -> Result<Option<CieOrFde<'bases, Section, R>>> {
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 Err(e) => {
1022 self.input.empty();
1023 Err(e)
1024 }
1025 Ok(None) => {
1026 self.input.empty();
1027 Ok(None)
1028 }
1029 Ok(Some(entry)) => Ok(Some(entry)),
1030 }
1031 }
1032}
1033
1034#[cfg(feature = "fallible-iterator")]
1035impl<'bases, Section, R> fallible_iterator::FallibleIterator for CfiEntriesIter<'bases, Section, R>
1036where
1037 R: Reader,
1038 Section: UnwindSection<R>,
1039{
1040 type Item = CieOrFde<'bases, Section, R>;
1041 type Error = Error;
1042
1043 fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
1044 CfiEntriesIter::next(self)
1045 }
1046}
1047
1048#[derive(Clone, Debug, PartialEq, Eq)]
1050pub enum CieOrFde<'bases, Section, R>
1051where
1052 R: Reader,
1053 Section: UnwindSection<R>,
1054{
1055 Cie(CommonInformationEntry<R>),
1057 Fde(PartialFrameDescriptionEntry<'bases, Section, R>),
1061}
1062
1063fn parse_cfi_entry<'bases, Section, R>(
1064 bases: &'bases BaseAddresses,
1065 section: &Section,
1066 input: &mut R,
1067) -> Result<Option<CieOrFde<'bases, Section, R>>>
1068where
1069 R: Reader,
1070 Section: UnwindSection<R>,
1071{
1072 let (offset, length, format) = loop {
1073 let offset = input.offset_from(section.section());
1074 let (length, format) = input.read_initial_length()?;
1075
1076 if Section::length_value_is_end_of_entries(length) {
1077 return Ok(None);
1078 }
1079
1080 if length.into_u64() != 0 || format != Format::Dwarf32 {
1086 break (offset, length, format);
1087 }
1088 };
1089
1090 let mut rest = input.split(length)?;
1091 let cie_offset_base = rest.offset_from(section.section());
1092 let cie_id_or_offset = match Section::cie_offset_encoding(format) {
1093 CieOffsetEncoding::U32 => rest.read_u32().map(u64::from)?,
1094 CieOffsetEncoding::U64 => rest.read_u64()?,
1095 };
1096
1097 if Section::is_cie(format, cie_id_or_offset) {
1098 let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?;
1099 Ok(Some(CieOrFde::Cie(cie)))
1100 } else {
1101 let cie_offset = R::Offset::from_u64(cie_id_or_offset)?;
1102 let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) {
1103 None => return Err(Error::OffsetOutOfBounds),
1104 Some(cie_offset) => cie_offset,
1105 };
1106
1107 let fde = PartialFrameDescriptionEntry {
1108 offset,
1109 length,
1110 format,
1111 cie_offset: cie_offset.into(),
1112 rest,
1113 section: section.clone(),
1114 bases,
1115 };
1116
1117 Ok(Some(CieOrFde::Fde(fde)))
1118 }
1119}
1120
1121#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1125pub struct Augmentation {
1126 lsda: Option<constants::DwEhPe>,
1136
1137 personality: Option<(constants::DwEhPe, Pointer)>,
1145
1146 fde_address_encoding: Option<constants::DwEhPe>,
1152
1153 is_signal_trampoline: bool,
1155}
1156
1157impl Augmentation {
1158 fn parse<Section, R>(
1159 augmentation_str: &mut R,
1160 bases: &BaseAddresses,
1161 address_size: u8,
1162 section: &Section,
1163 input: &mut R,
1164 ) -> Result<Augmentation>
1165 where
1166 R: Reader,
1167 Section: UnwindSection<R>,
1168 {
1169 debug_assert!(
1170 !augmentation_str.is_empty(),
1171 "Augmentation::parse should only be called if we have an augmentation"
1172 );
1173
1174 let mut augmentation = Augmentation::default();
1175
1176 let mut parsed_first = false;
1177 let mut data = None;
1178
1179 while !augmentation_str.is_empty() {
1180 let ch = augmentation_str.read_u8()?;
1181 match ch {
1182 b'z' => {
1183 if parsed_first {
1184 return Err(Error::UnknownAugmentation);
1185 }
1186
1187 let augmentation_length = input.read_uleb128().and_then(R::Offset::from_u64)?;
1188 data = Some(input.split(augmentation_length)?);
1189 }
1190 b'L' => {
1191 let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1192 let encoding = parse_pointer_encoding(rest)?;
1193 augmentation.lsda = Some(encoding);
1194 }
1195 b'P' => {
1196 let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1197 let encoding = parse_pointer_encoding(rest)?;
1198 let parameters = PointerEncodingParameters {
1199 bases: &bases.eh_frame,
1200 func_base: None,
1201 address_size,
1202 section: section.section(),
1203 };
1204
1205 let personality = parse_encoded_pointer(encoding, ¶meters, rest)?;
1206 augmentation.personality = Some((encoding, personality));
1207 }
1208 b'R' => {
1209 let rest = data.as_mut().ok_or(Error::UnknownAugmentation)?;
1210 let encoding = parse_pointer_encoding(rest)?;
1211 augmentation.fde_address_encoding = Some(encoding);
1212 }
1213 b'S' => augmentation.is_signal_trampoline = true,
1214 _ => return Err(Error::UnknownAugmentation),
1215 }
1216
1217 parsed_first = true;
1218 }
1219
1220 Ok(augmentation)
1221 }
1222}
1223
1224#[derive(Clone, Debug, Default, PartialEq, Eq)]
1226struct AugmentationData {
1227 lsda: Option<Pointer>,
1228}
1229
1230impl AugmentationData {
1231 fn parse<R: Reader>(
1232 augmentation: &Augmentation,
1233 encoding_parameters: &PointerEncodingParameters<'_, R>,
1234 input: &mut R,
1235 ) -> Result<AugmentationData> {
1236 let aug_data_len = input.read_uleb128().and_then(R::Offset::from_u64)?;
1243 let rest = &mut input.split(aug_data_len)?;
1244 let mut augmentation_data = AugmentationData::default();
1245 if let Some(encoding) = augmentation.lsda {
1246 let lsda = parse_encoded_pointer(encoding, encoding_parameters, rest)?;
1247 augmentation_data.lsda = Some(lsda);
1248 }
1249 Ok(augmentation_data)
1250 }
1251}
1252
1253#[derive(Clone, Debug, PartialEq, Eq)]
1257pub struct CommonInformationEntry<R, Offset = <R as Reader>::Offset>
1258where
1259 R: Reader<Offset = Offset>,
1260 Offset: ReaderOffset,
1261{
1262 offset: Offset,
1264
1265 length: Offset,
1270
1271 format: Format,
1272
1273 version: u8,
1276
1277 augmentation: Option<Augmentation>,
1279
1280 address_size: u8,
1284
1285 code_alignment_factor: u64,
1288
1289 data_alignment_factor: i64,
1292
1293 return_address_register: Register,
1297
1298 initial_instructions: R,
1309}
1310
1311impl<R: Reader> CommonInformationEntry<R> {
1312 fn parse<Section: UnwindSection<R>>(
1313 bases: &BaseAddresses,
1314 section: &Section,
1315 input: &mut R,
1316 ) -> Result<CommonInformationEntry<R>> {
1317 match parse_cfi_entry(bases, section, input)? {
1318 Some(CieOrFde::Cie(cie)) => Ok(cie),
1319 Some(CieOrFde::Fde(_)) => Err(Error::NotCieId),
1320 None => Err(Error::NoEntryAtGivenOffset),
1321 }
1322 }
1323
1324 fn parse_rest<Section: UnwindSection<R>>(
1325 offset: R::Offset,
1326 length: R::Offset,
1327 format: Format,
1328 bases: &BaseAddresses,
1329 section: &Section,
1330 mut rest: R,
1331 ) -> Result<CommonInformationEntry<R>> {
1332 let version = rest.read_u8()?;
1333
1334 match version {
1338 1 | 3 | 4 => (),
1339 _ => return Err(Error::UnknownVersion(u64::from(version))),
1340 }
1341
1342 let mut augmentation_string = rest.read_null_terminated_slice()?;
1343
1344 let address_size = if Section::has_address_and_segment_sizes(version) {
1345 let address_size = rest.read_address_size()?;
1346 let segment_size = rest.read_u8()?;
1347 if segment_size != 0 {
1348 return Err(Error::UnsupportedSegmentSize);
1349 }
1350 address_size
1351 } else {
1352 section.address_size()
1353 };
1354
1355 let code_alignment_factor = rest.read_uleb128()?;
1356 let data_alignment_factor = rest.read_sleb128()?;
1357
1358 let return_address_register = if version == 1 {
1359 Register(rest.read_u8()?.into())
1360 } else {
1361 rest.read_uleb128().and_then(Register::from_u64)?
1362 };
1363
1364 let augmentation = if augmentation_string.is_empty() {
1365 None
1366 } else {
1367 Some(Augmentation::parse(
1368 &mut augmentation_string,
1369 bases,
1370 address_size,
1371 section,
1372 &mut rest,
1373 )?)
1374 };
1375
1376 let entry = CommonInformationEntry {
1377 offset,
1378 length,
1379 format,
1380 version,
1381 augmentation,
1382 address_size,
1383 code_alignment_factor,
1384 data_alignment_factor,
1385 return_address_register,
1386 initial_instructions: rest,
1387 };
1388
1389 Ok(entry)
1390 }
1391}
1392
1393impl<R: Reader> CommonInformationEntry<R> {
1398 pub fn offset(&self) -> R::Offset {
1400 self.offset
1401 }
1402
1403 pub fn encoding(&self) -> Encoding {
1405 Encoding {
1406 format: self.format,
1407 version: u16::from(self.version),
1408 address_size: self.address_size,
1409 }
1410 }
1411
1412 pub fn address_size(&self) -> u8 {
1414 self.address_size
1415 }
1416
1417 pub fn instructions<'a, Section>(
1422 &self,
1423 section: &'a Section,
1424 bases: &'a BaseAddresses,
1425 ) -> CallFrameInstructionIter<'a, R>
1426 where
1427 Section: UnwindSection<R>,
1428 {
1429 CallFrameInstructionIter {
1430 input: self.initial_instructions.clone(),
1431 address_encoding: None,
1432 parameters: PointerEncodingParameters {
1433 bases: &bases.eh_frame,
1434 func_base: None,
1435 address_size: self.address_size,
1436 section: section.section(),
1437 },
1438 vendor: section.vendor(),
1439 }
1440 }
1441
1442 pub fn entry_len(&self) -> R::Offset {
1447 self.length
1448 }
1449
1450 pub fn version(&self) -> u8 {
1453 self.version
1454 }
1455
1456 pub fn augmentation(&self) -> Option<&Augmentation> {
1461 self.augmentation.as_ref()
1462 }
1463
1464 pub fn has_lsda(&self) -> bool {
1466 self.augmentation.map_or(false, |a| a.lsda.is_some())
1467 }
1468
1469 pub fn lsda_encoding(&self) -> Option<constants::DwEhPe> {
1471 self.augmentation.and_then(|a| a.lsda)
1472 }
1473
1474 pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> {
1477 self.augmentation.as_ref().and_then(|a| a.personality)
1478 }
1479
1480 pub fn personality(&self) -> Option<Pointer> {
1483 self.augmentation
1484 .as_ref()
1485 .and_then(|a| a.personality)
1486 .map(|(_, p)| p)
1487 }
1488
1489 pub fn fde_address_encoding(&self) -> Option<constants::DwEhPe> {
1491 self.augmentation.and_then(|a| a.fde_address_encoding)
1492 }
1493
1494 pub fn is_signal_trampoline(&self) -> bool {
1496 self.augmentation.map_or(false, |a| a.is_signal_trampoline)
1497 }
1498
1499 pub fn code_alignment_factor(&self) -> u64 {
1502 self.code_alignment_factor
1503 }
1504
1505 pub fn data_alignment_factor(&self) -> i64 {
1508 self.data_alignment_factor
1509 }
1510
1511 pub fn return_address_register(&self) -> Register {
1515 self.return_address_register
1516 }
1517}
1518
1519#[derive(Clone, Debug, PartialEq, Eq)]
1523pub struct PartialFrameDescriptionEntry<'bases, Section, R>
1524where
1525 R: Reader,
1526 Section: UnwindSection<R>,
1527{
1528 offset: R::Offset,
1529 length: R::Offset,
1530 format: Format,
1531 cie_offset: Section::Offset,
1532 rest: R,
1533 section: Section,
1534 bases: &'bases BaseAddresses,
1535}
1536
1537impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R>
1538where
1539 R: Reader,
1540 Section: UnwindSection<R>,
1541{
1542 fn parse_partial(
1543 section: &Section,
1544 bases: &'bases BaseAddresses,
1545 input: &mut R,
1546 ) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> {
1547 match parse_cfi_entry(bases, section, input)? {
1548 Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer),
1549 Some(CieOrFde::Fde(partial)) => Ok(partial),
1550 None => Err(Error::NoEntryAtGivenOffset),
1551 }
1552 }
1553
1554 pub fn parse<F>(&self, get_cie: F) -> Result<FrameDescriptionEntry<R>>
1560 where
1561 F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
1562 {
1563 FrameDescriptionEntry::parse_rest(
1564 self.offset,
1565 self.length,
1566 self.format,
1567 self.cie_offset,
1568 self.rest.clone(),
1569 &self.section,
1570 self.bases,
1571 get_cie,
1572 )
1573 }
1574
1575 pub fn offset(&self) -> R::Offset {
1577 self.offset
1578 }
1579
1580 pub fn cie_offset(&self) -> Section::Offset {
1582 self.cie_offset
1583 }
1584
1585 pub fn entry_len(&self) -> R::Offset {
1590 self.length
1591 }
1592}
1593
1594#[derive(Clone, Debug, PartialEq, Eq)]
1596pub struct FrameDescriptionEntry<R, Offset = <R as Reader>::Offset>
1597where
1598 R: Reader<Offset = Offset>,
1599 Offset: ReaderOffset,
1600{
1601 offset: Offset,
1603
1604 length: Offset,
1609
1610 format: Format,
1611
1612 cie: CommonInformationEntry<R, Offset>,
1617
1618 initial_address: u64,
1622
1623 address_range: u64,
1625
1626 augmentation: Option<AugmentationData>,
1628
1629 instructions: R,
1634}
1635
1636impl<R: Reader> FrameDescriptionEntry<R> {
1637 fn parse_rest<Section, F>(
1638 offset: R::Offset,
1639 length: R::Offset,
1640 format: Format,
1641 cie_pointer: Section::Offset,
1642 mut rest: R,
1643 section: &Section,
1644 bases: &BaseAddresses,
1645 mut get_cie: F,
1646 ) -> Result<FrameDescriptionEntry<R>>
1647 where
1648 Section: UnwindSection<R>,
1649 F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result<CommonInformationEntry<R>>,
1650 {
1651 let cie = get_cie(section, bases, cie_pointer)?;
1652
1653 let mut parameters = PointerEncodingParameters {
1654 bases: &bases.eh_frame,
1655 func_base: None,
1656 address_size: cie.address_size,
1657 section: section.section(),
1658 };
1659
1660 let (initial_address, address_range) = Self::parse_addresses(&mut rest, &cie, ¶meters)?;
1661 parameters.func_base = Some(initial_address);
1662
1663 let aug_data = if let Some(ref augmentation) = cie.augmentation {
1664 Some(AugmentationData::parse(
1665 augmentation,
1666 ¶meters,
1667 &mut rest,
1668 )?)
1669 } else {
1670 None
1671 };
1672
1673 let entry = FrameDescriptionEntry {
1674 offset,
1675 length,
1676 format,
1677 cie,
1678 initial_address,
1679 address_range,
1680 augmentation: aug_data,
1681 instructions: rest,
1682 };
1683
1684 Ok(entry)
1685 }
1686
1687 fn parse_addresses(
1688 input: &mut R,
1689 cie: &CommonInformationEntry<R>,
1690 parameters: &PointerEncodingParameters<'_, R>,
1691 ) -> Result<(u64, u64)> {
1692 let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding);
1693 if let Some(encoding) = encoding {
1694 let initial_address = parse_encoded_pointer(encoding, parameters, input)?.pointer();
1696 let address_range = parse_encoded_value(encoding, parameters, input)?;
1697 Ok((initial_address, address_range))
1698 } else {
1699 let initial_address = input.read_address(cie.address_size)?;
1700 let address_range = input.read_address(cie.address_size)?;
1701 Ok((initial_address, address_range))
1702 }
1703 }
1704
1705 #[inline]
1707 pub fn rows<'a, 'ctx, Section, S>(
1708 &self,
1709 section: &'a Section,
1710 bases: &'a BaseAddresses,
1711 ctx: &'ctx mut UnwindContext<R::Offset, S>,
1712 ) -> Result<UnwindTable<'a, 'ctx, R, S>>
1713 where
1714 Section: UnwindSection<R>,
1715 S: UnwindContextStorage<R::Offset>,
1716 {
1717 UnwindTable::new(section, bases, ctx, self)
1718 }
1719
1720 pub fn unwind_info_for_address<'ctx, Section, S>(
1727 &self,
1728 section: &Section,
1729 bases: &BaseAddresses,
1730 ctx: &'ctx mut UnwindContext<R::Offset, S>,
1731 address: u64,
1732 ) -> Result<&'ctx UnwindTableRow<R::Offset, S>>
1733 where
1734 Section: UnwindSection<R>,
1735 S: UnwindContextStorage<R::Offset>,
1736 {
1737 let mut table = self.rows(section, bases, ctx)?;
1738 while let Some(row) = table.next_row()? {
1739 if row.contains(address) {
1740 return Ok(table.ctx.row());
1741 }
1742 }
1743 Err(Error::NoUnwindInfoForAddress)
1744 }
1745}
1746
1747#[allow(clippy::len_without_is_empty)]
1752impl<R: Reader> FrameDescriptionEntry<R> {
1753 pub fn offset(&self) -> R::Offset {
1755 self.offset
1756 }
1757
1758 pub fn cie(&self) -> &CommonInformationEntry<R> {
1760 &self.cie
1761 }
1762
1763 pub fn entry_len(&self) -> R::Offset {
1768 self.length
1769 }
1770
1771 pub fn instructions<'a, Section>(
1779 &self,
1780 section: &'a Section,
1781 bases: &'a BaseAddresses,
1782 ) -> CallFrameInstructionIter<'a, R>
1783 where
1784 Section: UnwindSection<R>,
1785 {
1786 CallFrameInstructionIter {
1787 input: self.instructions.clone(),
1788 address_encoding: self.cie.augmentation().and_then(|a| a.fde_address_encoding),
1789 parameters: PointerEncodingParameters {
1790 bases: &bases.eh_frame,
1791 func_base: None,
1792 address_size: self.cie.address_size,
1793 section: section.section(),
1794 },
1795 vendor: section.vendor(),
1796 }
1797 }
1798
1799 pub fn initial_address(&self) -> u64 {
1801 self.initial_address
1802 }
1803
1804 pub fn end_address(&self) -> u64 {
1809 self.initial_address
1810 .wrapping_add_sized(self.address_range, self.cie.address_size)
1811 }
1812
1813 pub fn len(&self) -> u64 {
1816 self.address_range
1817 }
1818
1819 pub fn contains(&self, address: u64) -> bool {
1825 self.initial_address() <= address && address < self.end_address()
1826 }
1827
1828 pub fn lsda(&self) -> Option<Pointer> {
1831 self.augmentation.as_ref().and_then(|a| a.lsda)
1832 }
1833
1834 #[inline]
1836 pub fn is_signal_trampoline(&self) -> bool {
1837 self.cie().is_signal_trampoline()
1838 }
1839
1840 #[inline]
1844 pub fn personality(&self) -> Option<Pointer> {
1845 self.cie().personality()
1846 }
1847}
1848
1849#[cfg_attr(
1852 feature = "read",
1853 doc = "
1854Normally you would only need to use [`StoreOnHeap`], which places the stack
1855on the heap using [`Box`]. This is the default storage type parameter for [`UnwindContext`].
1856
1857You may want to supply your own storage type for one of the following reasons:
1858
1859 1. In rare cases you may run into failed unwinds due to the fixed stack size
1860 used by [`StoreOnHeap`], so you may want to try a larger `Box`. If denial
1861 of service is not a concern, then you could also try a `Vec`-based stack which
1862 can grow as needed.
1863 2. You may want to avoid heap allocations entirely. You can use a fixed-size
1864 stack with in-line arrays, which will place the entire storage in-line into
1865 [`UnwindContext`].
1866"
1867)]
1868pub trait UnwindContextStorage<T: ReaderOffset>: Sized {
1900 type Rules: ArrayLike<Item = (Register, RegisterRule<T>)>;
1904
1905 type Stack: ArrayLike<Item = UnwindTableRow<T, Self>>;
1907}
1908
1909#[cfg(feature = "read")]
1910const MAX_RULES: usize = 192;
1911#[cfg(feature = "read")]
1912const MAX_UNWIND_STACK_DEPTH: usize = 4;
1913
1914#[cfg(feature = "read")]
1915impl<T: ReaderOffset> UnwindContextStorage<T> for StoreOnHeap {
1916 type Rules = [(Register, RegisterRule<T>); MAX_RULES];
1917 type Stack = Box<[UnwindTableRow<T, Self>; MAX_UNWIND_STACK_DEPTH]>;
1918}
1919
1920#[derive(Clone, PartialEq, Eq)]
1954pub struct UnwindContext<T, S = StoreOnHeap>
1955where
1956 T: ReaderOffset,
1957 S: UnwindContextStorage<T>,
1958{
1959 stack: ArrayVec<S::Stack>,
1963
1964 initial_rule: Option<(Register, RegisterRule<T>)>,
1973
1974 is_initialized: bool,
1975}
1976
1977impl<T, S> Debug for UnwindContext<T, S>
1978where
1979 T: ReaderOffset,
1980 S: UnwindContextStorage<T>,
1981{
1982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1983 f.debug_struct("UnwindContext")
1984 .field("stack", &self.stack)
1985 .field("initial_rule", &self.initial_rule)
1986 .field("is_initialized", &self.is_initialized)
1987 .finish()
1988 }
1989}
1990
1991impl<T, S> Default for UnwindContext<T, S>
1992where
1993 T: ReaderOffset,
1994 S: UnwindContextStorage<T>,
1995{
1996 fn default() -> Self {
1997 Self::new_in()
1998 }
1999}
2000
2001#[cfg(feature = "read")]
2002impl<T: ReaderOffset> UnwindContext<T> {
2003 pub fn new() -> Self {
2005 Self::new_in()
2006 }
2007}
2008
2009impl<T, S> UnwindContext<T, S>
2014where
2015 T: ReaderOffset,
2016 S: UnwindContextStorage<T>,
2017{
2018 pub fn new_in() -> Self {
2020 let mut ctx = UnwindContext {
2021 stack: Default::default(),
2022 initial_rule: None,
2023 is_initialized: false,
2024 };
2025 ctx.reset();
2026 ctx
2027 }
2028
2029 fn initialize<Section, R>(
2031 &mut self,
2032 section: &Section,
2033 bases: &BaseAddresses,
2034 cie: &CommonInformationEntry<R>,
2035 ) -> Result<()>
2036 where
2037 R: Reader<Offset = T>,
2038 Section: UnwindSection<R>,
2039 {
2040 self.reset();
2042
2043 let mut table = UnwindTable::new_for_cie(section, bases, self, cie);
2044 while table.next_row()?.is_some() {}
2045
2046 self.save_initial_rules()?;
2047 Ok(())
2048 }
2049
2050 fn reset(&mut self) {
2051 self.stack.clear();
2052 self.stack.try_push(UnwindTableRow::default()).unwrap();
2053 debug_assert!(self.stack[0].is_default());
2054 self.initial_rule = None;
2055 self.is_initialized = false;
2056 }
2057
2058 fn row(&self) -> &UnwindTableRow<T, S> {
2059 self.stack.last().unwrap()
2060 }
2061
2062 fn row_mut(&mut self) -> &mut UnwindTableRow<T, S> {
2063 self.stack.last_mut().unwrap()
2064 }
2065
2066 fn save_initial_rules(&mut self) -> Result<()> {
2067 debug_assert!(!self.is_initialized);
2068 self.initial_rule = match *self.stack.last().unwrap().registers.rules {
2069 [] => Some((Register(0), RegisterRule::Undefined)),
2072 [ref rule] => Some(rule.clone()),
2073 _ => {
2074 let rules = self.stack.last().unwrap().clone();
2075 self.stack
2076 .try_insert(0, rules)
2077 .map_err(|_| Error::StackFull)?;
2078 None
2079 }
2080 };
2081 self.is_initialized = true;
2082 Ok(())
2083 }
2084
2085 fn start_address(&self) -> u64 {
2086 self.row().start_address
2087 }
2088
2089 fn set_start_address(&mut self, start_address: u64) {
2090 let row = self.row_mut();
2091 row.start_address = start_address;
2092 }
2093
2094 fn set_register_rule(&mut self, register: Register, rule: RegisterRule<T>) -> Result<()> {
2095 let row = self.row_mut();
2096 row.registers.set(register, rule)
2097 }
2098
2099 fn get_initial_rule(&self, register: Register) -> Option<RegisterRule<T>> {
2102 if !self.is_initialized {
2103 return None;
2104 }
2105 Some(match self.initial_rule {
2106 None => self.stack[0].registers.get(register),
2107 Some((r, ref rule)) if r == register => rule.clone(),
2108 _ => RegisterRule::Undefined,
2109 })
2110 }
2111
2112 fn set_cfa(&mut self, cfa: CfaRule<T>) {
2113 self.row_mut().cfa = cfa;
2114 }
2115
2116 fn cfa_mut(&mut self) -> &mut CfaRule<T> {
2117 &mut self.row_mut().cfa
2118 }
2119
2120 fn push_row(&mut self) -> Result<()> {
2121 let new_row = self.row().clone();
2122 self.stack.try_push(new_row).map_err(|_| Error::StackFull)
2123 }
2124
2125 fn pop_row(&mut self) -> Result<()> {
2126 let min_size = if self.is_initialized && self.initial_rule.is_none() {
2127 2
2128 } else {
2129 1
2130 };
2131 if self.stack.len() <= min_size {
2132 return Err(Error::PopWithEmptyStack);
2133 }
2134 self.stack.pop().unwrap();
2135 Ok(())
2136 }
2137}
2138
2139#[derive(Debug)]
2196pub struct UnwindTable<'a, 'ctx, R, S = StoreOnHeap>
2197where
2198 R: Reader,
2199 S: UnwindContextStorage<R::Offset>,
2200{
2201 code_alignment_factor: Wrapping<u64>,
2202 data_alignment_factor: Wrapping<i64>,
2203 address_size: u8,
2204 next_start_address: u64,
2205 last_end_address: u64,
2206 returned_last_row: bool,
2207 current_row_valid: bool,
2208 instructions: CallFrameInstructionIter<'a, R>,
2209 ctx: &'ctx mut UnwindContext<R::Offset, S>,
2210}
2211
2212impl<'a, 'ctx, R, S> UnwindTable<'a, 'ctx, R, S>
2217where
2218 R: Reader,
2219 S: UnwindContextStorage<R::Offset>,
2220{
2221 pub fn new<Section: UnwindSection<R>>(
2224 section: &'a Section,
2225 bases: &'a BaseAddresses,
2226 ctx: &'ctx mut UnwindContext<R::Offset, S>,
2227 fde: &FrameDescriptionEntry<R>,
2228 ) -> Result<Self> {
2229 ctx.initialize(section, bases, fde.cie())?;
2230 Ok(Self::new_for_fde(section, bases, ctx, fde))
2231 }
2232
2233 fn new_for_fde<Section: UnwindSection<R>>(
2234 section: &'a Section,
2235 bases: &'a BaseAddresses,
2236 ctx: &'ctx mut UnwindContext<R::Offset, S>,
2237 fde: &FrameDescriptionEntry<R>,
2238 ) -> Self {
2239 assert!(ctx.stack.len() >= 1);
2240 UnwindTable {
2241 code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()),
2242 data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()),
2243 address_size: fde.cie().address_size,
2244 next_start_address: fde.initial_address(),
2245 last_end_address: fde.end_address(),
2246 returned_last_row: false,
2247 current_row_valid: false,
2248 instructions: fde.instructions(section, bases),
2249 ctx,
2250 }
2251 }
2252
2253 fn new_for_cie<Section: UnwindSection<R>>(
2254 section: &'a Section,
2255 bases: &'a BaseAddresses,
2256 ctx: &'ctx mut UnwindContext<R::Offset, S>,
2257 cie: &CommonInformationEntry<R>,
2258 ) -> Self {
2259 assert!(ctx.stack.len() >= 1);
2260 UnwindTable {
2261 code_alignment_factor: Wrapping(cie.code_alignment_factor()),
2262 data_alignment_factor: Wrapping(cie.data_alignment_factor()),
2263 address_size: cie.address_size,
2264 next_start_address: 0,
2265 last_end_address: 0,
2266 returned_last_row: false,
2267 current_row_valid: false,
2268 instructions: cie.instructions(section, bases),
2269 ctx,
2270 }
2271 }
2272
2273 pub fn next_row(&mut self) -> Result<Option<&UnwindTableRow<R::Offset, S>>> {
2279 assert!(self.ctx.stack.len() >= 1);
2280 self.ctx.set_start_address(self.next_start_address);
2281 self.current_row_valid = false;
2282
2283 loop {
2284 match self.instructions.next() {
2285 Err(e) => return Err(e),
2286
2287 Ok(None) => {
2288 if self.returned_last_row {
2289 return Ok(None);
2290 }
2291
2292 let row = self.ctx.row_mut();
2293 row.end_address = self.last_end_address;
2294
2295 self.returned_last_row = true;
2296 self.current_row_valid = true;
2297 return Ok(Some(row));
2298 }
2299
2300 Ok(Some(instruction)) => {
2301 if self.evaluate(instruction)? {
2302 self.current_row_valid = true;
2303 return Ok(Some(self.ctx.row()));
2304 }
2305 }
2306 };
2307 }
2308 }
2309
2310 pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow<R::Offset, S>> {
2312 if self.current_row_valid {
2313 Some(self.ctx.row())
2314 } else {
2315 None
2316 }
2317 }
2318
2319 fn evaluate(&mut self, instruction: CallFrameInstruction<R::Offset>) -> Result<bool> {
2322 use crate::CallFrameInstruction::*;
2323
2324 match instruction {
2325 SetLoc { address } => {
2328 if address < self.ctx.start_address() {
2329 return Err(Error::InvalidAddressRange);
2330 }
2331
2332 self.next_start_address = address;
2333 self.ctx.row_mut().end_address = self.next_start_address;
2334 return Ok(true);
2335 }
2336 AdvanceLoc { delta } => {
2337 let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor;
2338 self.next_start_address = self
2339 .ctx
2340 .start_address()
2341 .add_sized(delta.0, self.address_size)?;
2342 self.ctx.row_mut().end_address = self.next_start_address;
2343 return Ok(true);
2344 }
2345
2346 DefCfa { register, offset } => {
2348 self.ctx.set_cfa(CfaRule::RegisterAndOffset {
2349 register,
2350 offset: offset as i64,
2351 });
2352 }
2353 DefCfaSf {
2354 register,
2355 factored_offset,
2356 } => {
2357 let data_align = self.data_alignment_factor;
2358 self.ctx.set_cfa(CfaRule::RegisterAndOffset {
2359 register,
2360 offset: (Wrapping(factored_offset) * data_align).0,
2361 });
2362 }
2363 DefCfaRegister { register } => {
2364 if let CfaRule::RegisterAndOffset {
2365 register: ref mut reg,
2366 ..
2367 } = *self.ctx.cfa_mut()
2368 {
2369 *reg = register;
2370 } else {
2371 return Err(Error::CfiInstructionInInvalidContext);
2372 }
2373 }
2374 DefCfaOffset { offset } => {
2375 if let CfaRule::RegisterAndOffset {
2376 offset: ref mut off,
2377 ..
2378 } = *self.ctx.cfa_mut()
2379 {
2380 *off = offset as i64;
2381 } else {
2382 return Err(Error::CfiInstructionInInvalidContext);
2383 }
2384 }
2385 DefCfaOffsetSf { factored_offset } => {
2386 if let CfaRule::RegisterAndOffset {
2387 offset: ref mut off,
2388 ..
2389 } = *self.ctx.cfa_mut()
2390 {
2391 let data_align = self.data_alignment_factor;
2392 *off = (Wrapping(factored_offset) * data_align).0;
2393 } else {
2394 return Err(Error::CfiInstructionInInvalidContext);
2395 }
2396 }
2397 DefCfaExpression { expression } => {
2398 self.ctx.set_cfa(CfaRule::Expression(expression));
2399 }
2400
2401 Undefined { register } => {
2403 self.ctx
2404 .set_register_rule(register, RegisterRule::Undefined)?;
2405 }
2406 SameValue { register } => {
2407 self.ctx
2408 .set_register_rule(register, RegisterRule::SameValue)?;
2409 }
2410 Offset {
2411 register,
2412 factored_offset,
2413 } => {
2414 let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
2415 self.ctx
2416 .set_register_rule(register, RegisterRule::Offset(offset.0))?;
2417 }
2418 OffsetExtendedSf {
2419 register,
2420 factored_offset,
2421 } => {
2422 let offset = Wrapping(factored_offset) * self.data_alignment_factor;
2423 self.ctx
2424 .set_register_rule(register, RegisterRule::Offset(offset.0))?;
2425 }
2426 ValOffset {
2427 register,
2428 factored_offset,
2429 } => {
2430 let offset = Wrapping(factored_offset as i64) * self.data_alignment_factor;
2431 self.ctx
2432 .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
2433 }
2434 ValOffsetSf {
2435 register,
2436 factored_offset,
2437 } => {
2438 let offset = Wrapping(factored_offset) * self.data_alignment_factor;
2439 self.ctx
2440 .set_register_rule(register, RegisterRule::ValOffset(offset.0))?;
2441 }
2442 Register {
2443 dest_register,
2444 src_register,
2445 } => {
2446 self.ctx
2447 .set_register_rule(dest_register, RegisterRule::Register(src_register))?;
2448 }
2449 Expression {
2450 register,
2451 expression,
2452 } => {
2453 let expression = RegisterRule::Expression(expression);
2454 self.ctx.set_register_rule(register, expression)?;
2455 }
2456 ValExpression {
2457 register,
2458 expression,
2459 } => {
2460 let expression = RegisterRule::ValExpression(expression);
2461 self.ctx.set_register_rule(register, expression)?;
2462 }
2463 Restore { register } => {
2464 let initial_rule = if let Some(rule) = self.ctx.get_initial_rule(register) {
2465 rule
2466 } else {
2467 return Err(Error::CfiInstructionInInvalidContext);
2470 };
2471
2472 self.ctx.set_register_rule(register, initial_rule)?;
2473 }
2474
2475 RememberState => {
2477 self.ctx.push_row()?;
2478 }
2479 RestoreState => {
2480 let start_address = self.ctx.start_address();
2482 self.ctx.pop_row()?;
2483 self.ctx.set_start_address(start_address);
2484 }
2485
2486 ArgsSize { size } => {
2489 self.ctx.row_mut().saved_args_size = size;
2490 }
2491
2492 NegateRaState => {
2494 let register = crate::AArch64::RA_SIGN_STATE;
2495 let value = match self.ctx.row().register(register) {
2496 RegisterRule::Undefined => 0,
2497 RegisterRule::Constant(value) => value,
2498 _ => return Err(Error::CfiInstructionInInvalidContext),
2499 };
2500 self.ctx
2501 .set_register_rule(register, RegisterRule::Constant(value ^ 1))?;
2502 }
2503
2504 Nop => {}
2506 };
2507
2508 Ok(false)
2509 }
2510}
2511
2512struct RegisterRuleMap<T, S = StoreOnHeap>
2534where
2535 T: ReaderOffset,
2536 S: UnwindContextStorage<T>,
2537{
2538 rules: ArrayVec<S::Rules>,
2539}
2540
2541impl<T, S> Debug for RegisterRuleMap<T, S>
2542where
2543 T: ReaderOffset,
2544 S: UnwindContextStorage<T>,
2545{
2546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2547 f.debug_struct("RegisterRuleMap")
2548 .field("rules", &self.rules)
2549 .finish()
2550 }
2551}
2552
2553impl<T, S> Clone for RegisterRuleMap<T, S>
2554where
2555 T: ReaderOffset,
2556 S: UnwindContextStorage<T>,
2557{
2558 fn clone(&self) -> Self {
2559 Self {
2560 rules: self.rules.clone(),
2561 }
2562 }
2563}
2564
2565impl<T, S> Default for RegisterRuleMap<T, S>
2566where
2567 T: ReaderOffset,
2568 S: UnwindContextStorage<T>,
2569{
2570 fn default() -> Self {
2571 RegisterRuleMap {
2572 rules: Default::default(),
2573 }
2574 }
2575}
2576
2577impl<T, S> RegisterRuleMap<T, S>
2582where
2583 T: ReaderOffset,
2584 S: UnwindContextStorage<T>,
2585{
2586 fn is_default(&self) -> bool {
2587 self.rules.is_empty()
2588 }
2589
2590 fn get(&self, register: Register) -> RegisterRule<T> {
2591 self.rules
2592 .iter()
2593 .find(|rule| rule.0 == register)
2594 .map(|r| {
2595 debug_assert!(r.1.is_defined());
2596 r.1.clone()
2597 })
2598 .unwrap_or(RegisterRule::Undefined)
2599 }
2600
2601 fn set(&mut self, register: Register, rule: RegisterRule<T>) -> Result<()> {
2602 if !rule.is_defined() {
2603 let idx = self
2604 .rules
2605 .iter()
2606 .enumerate()
2607 .find(|&(_, r)| r.0 == register)
2608 .map(|(i, _)| i);
2609 if let Some(idx) = idx {
2610 self.rules.swap_remove(idx);
2611 }
2612 return Ok(());
2613 }
2614
2615 for &mut (reg, ref mut old_rule) in &mut *self.rules {
2616 debug_assert!(old_rule.is_defined());
2617 if reg == register {
2618 *old_rule = rule;
2619 return Ok(());
2620 }
2621 }
2622
2623 self.rules
2624 .try_push((register, rule))
2625 .map_err(|_| Error::TooManyRegisterRules)
2626 }
2627
2628 fn iter(&self) -> RegisterRuleIter<'_, T> {
2629 RegisterRuleIter(self.rules.iter())
2630 }
2631}
2632
2633impl<'a, R, S> FromIterator<&'a (Register, RegisterRule<R>)> for RegisterRuleMap<R, S>
2634where
2635 R: 'a + ReaderOffset,
2636 S: UnwindContextStorage<R>,
2637{
2638 fn from_iter<T>(iter: T) -> Self
2639 where
2640 T: IntoIterator<Item = &'a (Register, RegisterRule<R>)>,
2641 {
2642 let iter = iter.into_iter();
2643 let mut rules = RegisterRuleMap::default();
2644 for &(reg, ref rule) in iter.filter(|r| r.1.is_defined()) {
2645 rules.set(reg, rule.clone()).expect(
2646 "This is only used in tests, impl isn't exposed publicly.
2647 If you trip this, fix your test",
2648 );
2649 }
2650 rules
2651 }
2652}
2653
2654impl<T, S> PartialEq for RegisterRuleMap<T, S>
2655where
2656 T: ReaderOffset + PartialEq,
2657 S: UnwindContextStorage<T>,
2658{
2659 fn eq(&self, rhs: &Self) -> bool {
2660 for &(reg, ref rule) in &*self.rules {
2661 debug_assert!(rule.is_defined());
2662 if *rule != rhs.get(reg) {
2663 return false;
2664 }
2665 }
2666
2667 for &(reg, ref rhs_rule) in &*rhs.rules {
2668 debug_assert!(rhs_rule.is_defined());
2669 if *rhs_rule != self.get(reg) {
2670 return false;
2671 }
2672 }
2673
2674 true
2675 }
2676}
2677
2678impl<T, S> Eq for RegisterRuleMap<T, S>
2679where
2680 T: ReaderOffset + Eq,
2681 S: UnwindContextStorage<T>,
2682{
2683}
2684
2685#[derive(Debug, Clone)]
2687pub struct RegisterRuleIter<'iter, T>(::core::slice::Iter<'iter, (Register, RegisterRule<T>)>)
2688where
2689 T: ReaderOffset;
2690
2691impl<'iter, T: ReaderOffset> Iterator for RegisterRuleIter<'iter, T> {
2692 type Item = &'iter (Register, RegisterRule<T>);
2693
2694 fn next(&mut self) -> Option<Self::Item> {
2695 self.0.next()
2696 }
2697}
2698
2699#[derive(PartialEq, Eq)]
2702pub struct UnwindTableRow<T, S = StoreOnHeap>
2703where
2704 T: ReaderOffset,
2705 S: UnwindContextStorage<T>,
2706{
2707 start_address: u64,
2708 end_address: u64,
2709 saved_args_size: u64,
2710 cfa: CfaRule<T>,
2711 registers: RegisterRuleMap<T, S>,
2712}
2713
2714impl<T, S> Debug for UnwindTableRow<T, S>
2715where
2716 T: ReaderOffset,
2717 S: UnwindContextStorage<T>,
2718{
2719 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2720 f.debug_struct("UnwindTableRow")
2721 .field("start_address", &self.start_address)
2722 .field("end_address", &self.end_address)
2723 .field("saved_args_size", &self.saved_args_size)
2724 .field("cfa", &self.cfa)
2725 .field("registers", &self.registers)
2726 .finish()
2727 }
2728}
2729
2730impl<T, S> Clone for UnwindTableRow<T, S>
2731where
2732 T: ReaderOffset,
2733 S: UnwindContextStorage<T>,
2734{
2735 fn clone(&self) -> Self {
2736 Self {
2737 start_address: self.start_address,
2738 end_address: self.end_address,
2739 saved_args_size: self.saved_args_size,
2740 cfa: self.cfa.clone(),
2741 registers: self.registers.clone(),
2742 }
2743 }
2744}
2745
2746impl<T, S> Default for UnwindTableRow<T, S>
2747where
2748 T: ReaderOffset,
2749 S: UnwindContextStorage<T>,
2750{
2751 fn default() -> Self {
2752 UnwindTableRow {
2753 start_address: 0,
2754 end_address: 0,
2755 saved_args_size: 0,
2756 cfa: Default::default(),
2757 registers: Default::default(),
2758 }
2759 }
2760}
2761
2762impl<T, S> UnwindTableRow<T, S>
2763where
2764 T: ReaderOffset,
2765 S: UnwindContextStorage<T>,
2766{
2767 fn is_default(&self) -> bool {
2768 self.start_address == 0
2769 && self.end_address == 0
2770 && self.cfa.is_default()
2771 && self.registers.is_default()
2772 }
2773
2774 pub fn start_address(&self) -> u64 {
2776 self.start_address
2777 }
2778
2779 pub fn end_address(&self) -> u64 {
2787 self.end_address
2788 }
2789
2790 pub fn contains(&self, address: u64) -> bool {
2793 self.start_address <= address && address < self.end_address
2794 }
2795
2796 pub fn saved_args_size(&self) -> u64 {
2801 self.saved_args_size
2802 }
2803
2804 pub fn cfa(&self) -> &CfaRule<T> {
2806 &self.cfa
2807 }
2808
2809 pub fn register(&self, register: Register) -> RegisterRule<T> {
2854 self.registers.get(register)
2855 }
2856
2857 pub fn registers(&self) -> RegisterRuleIter<'_, T> {
2873 self.registers.iter()
2874 }
2875}
2876
2877#[derive(Clone, Debug, PartialEq, Eq)]
2879pub enum CfaRule<T: ReaderOffset> {
2880 RegisterAndOffset {
2882 register: Register,
2884 offset: i64,
2886 },
2887 Expression(UnwindExpression<T>),
2889}
2890
2891impl<T: ReaderOffset> Default for CfaRule<T> {
2892 fn default() -> Self {
2893 CfaRule::RegisterAndOffset {
2894 register: Register(0),
2895 offset: 0,
2896 }
2897 }
2898}
2899
2900impl<T: ReaderOffset> CfaRule<T> {
2901 fn is_default(&self) -> bool {
2902 match *self {
2903 CfaRule::RegisterAndOffset { register, offset } => {
2904 register == Register(0) && offset == 0
2905 }
2906 _ => false,
2907 }
2908 }
2909}
2910
2911#[derive(Clone, Debug, PartialEq, Eq)]
2918#[non_exhaustive]
2919pub enum RegisterRule<T: ReaderOffset> {
2920 Undefined,
2923
2924 SameValue,
2928
2929 Offset(i64),
2932
2933 ValOffset(i64),
2936
2937 Register(Register),
2940
2941 Expression(UnwindExpression<T>),
2944
2945 ValExpression(UnwindExpression<T>),
2948
2949 Architectural,
2951
2952 Constant(u64),
2954}
2955
2956impl<T: ReaderOffset> RegisterRule<T> {
2957 fn is_defined(&self) -> bool {
2958 !matches!(*self, RegisterRule::Undefined)
2959 }
2960}
2961
2962#[derive(Clone, Debug, PartialEq, Eq)]
2964#[non_exhaustive]
2965pub enum CallFrameInstruction<T: ReaderOffset> {
2966 SetLoc {
2977 address: u64,
2979 },
2980
2981 AdvanceLoc {
2993 delta: u32,
2995 },
2996
2997 DefCfa {
3005 register: Register,
3007 offset: u64,
3009 },
3010
3011 DefCfaSf {
3019 register: Register,
3021 factored_offset: i64,
3023 },
3024
3025 DefCfaRegister {
3033 register: Register,
3035 },
3036
3037 DefCfaOffset {
3045 offset: u64,
3047 },
3048
3049 DefCfaOffsetSf {
3058 factored_offset: i64,
3060 },
3061
3062 DefCfaExpression {
3069 expression: UnwindExpression<T>,
3071 },
3072
3073 Undefined {
3080 register: Register,
3082 },
3083
3084 SameValue {
3090 register: Register,
3092 },
3093
3094 Offset {
3105 register: Register,
3107 factored_offset: u64,
3109 },
3110
3111 OffsetExtendedSf {
3120 register: Register,
3122 factored_offset: i64,
3124 },
3125
3126 ValOffset {
3134 register: Register,
3136 factored_offset: u64,
3138 },
3139
3140 ValOffsetSf {
3148 register: Register,
3150 factored_offset: i64,
3152 },
3153
3154 Register {
3161 dest_register: Register,
3163 src_register: Register,
3166 },
3167
3168 Expression {
3178 register: Register,
3180 expression: UnwindExpression<T>,
3182 },
3183
3184 ValExpression {
3195 register: Register,
3197 expression: UnwindExpression<T>,
3199 },
3200
3201 Restore {
3211 register: Register,
3213 },
3214
3215 RememberState,
3222
3223 RestoreState,
3229
3230 ArgsSize {
3238 size: u64,
3240 },
3241
3242 NegateRaState,
3252
3253 Nop,
3259}
3260
3261const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000;
3262const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK;
3263
3264impl<T: ReaderOffset> CallFrameInstruction<T> {
3265 fn parse<R: Reader<Offset = T>>(
3266 input: &mut R,
3267 address_encoding: Option<DwEhPe>,
3268 parameters: &PointerEncodingParameters<'_, R>,
3269 vendor: Vendor,
3270 ) -> Result<CallFrameInstruction<T>> {
3271 let instruction = input.read_u8()?;
3272 let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK;
3273
3274 if high_bits == constants::DW_CFA_advance_loc.0 {
3275 let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK;
3276 return Ok(CallFrameInstruction::AdvanceLoc {
3277 delta: u32::from(delta),
3278 });
3279 }
3280
3281 if high_bits == constants::DW_CFA_offset.0 {
3282 let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3283 let offset = input.read_uleb128()?;
3284 return Ok(CallFrameInstruction::Offset {
3285 register,
3286 factored_offset: offset,
3287 });
3288 }
3289
3290 if high_bits == constants::DW_CFA_restore.0 {
3291 let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3292 return Ok(CallFrameInstruction::Restore { register });
3293 }
3294
3295 debug_assert_eq!(high_bits, 0);
3296 let instruction = constants::DwCfa(instruction);
3297
3298 match instruction {
3299 constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop),
3300
3301 constants::DW_CFA_set_loc => {
3302 let address = if let Some(encoding) = address_encoding {
3303 parse_encoded_pointer(encoding, parameters, input)?.direct()?
3304 } else {
3305 input.read_address(parameters.address_size)?
3306 };
3307 Ok(CallFrameInstruction::SetLoc { address })
3308 }
3309
3310 constants::DW_CFA_advance_loc1 => {
3311 let delta = input.read_u8()?;
3312 Ok(CallFrameInstruction::AdvanceLoc {
3313 delta: u32::from(delta),
3314 })
3315 }
3316
3317 constants::DW_CFA_advance_loc2 => {
3318 let delta = input.read_u16()?;
3319 Ok(CallFrameInstruction::AdvanceLoc {
3320 delta: u32::from(delta),
3321 })
3322 }
3323
3324 constants::DW_CFA_advance_loc4 => {
3325 let delta = input.read_u32()?;
3326 Ok(CallFrameInstruction::AdvanceLoc { delta })
3327 }
3328
3329 constants::DW_CFA_offset_extended => {
3330 let register = input.read_uleb128().and_then(Register::from_u64)?;
3331 let offset = input.read_uleb128()?;
3332 Ok(CallFrameInstruction::Offset {
3333 register,
3334 factored_offset: offset,
3335 })
3336 }
3337
3338 constants::DW_CFA_restore_extended => {
3339 let register = input.read_uleb128().and_then(Register::from_u64)?;
3340 Ok(CallFrameInstruction::Restore { register })
3341 }
3342
3343 constants::DW_CFA_undefined => {
3344 let register = input.read_uleb128().and_then(Register::from_u64)?;
3345 Ok(CallFrameInstruction::Undefined { register })
3346 }
3347
3348 constants::DW_CFA_same_value => {
3349 let register = input.read_uleb128().and_then(Register::from_u64)?;
3350 Ok(CallFrameInstruction::SameValue { register })
3351 }
3352
3353 constants::DW_CFA_register => {
3354 let dest = input.read_uleb128().and_then(Register::from_u64)?;
3355 let src = input.read_uleb128().and_then(Register::from_u64)?;
3356 Ok(CallFrameInstruction::Register {
3357 dest_register: dest,
3358 src_register: src,
3359 })
3360 }
3361
3362 constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState),
3363
3364 constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState),
3365
3366 constants::DW_CFA_def_cfa => {
3367 let register = input.read_uleb128().and_then(Register::from_u64)?;
3368 let offset = input.read_uleb128()?;
3369 Ok(CallFrameInstruction::DefCfa { register, offset })
3370 }
3371
3372 constants::DW_CFA_def_cfa_register => {
3373 let register = input.read_uleb128().and_then(Register::from_u64)?;
3374 Ok(CallFrameInstruction::DefCfaRegister { register })
3375 }
3376
3377 constants::DW_CFA_def_cfa_offset => {
3378 let offset = input.read_uleb128()?;
3379 Ok(CallFrameInstruction::DefCfaOffset { offset })
3380 }
3381
3382 constants::DW_CFA_def_cfa_expression => {
3383 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3384 let offset = input.offset_from(parameters.section);
3385 input.skip(length)?;
3386 Ok(CallFrameInstruction::DefCfaExpression {
3387 expression: UnwindExpression { offset, length },
3388 })
3389 }
3390
3391 constants::DW_CFA_expression => {
3392 let register = input.read_uleb128().and_then(Register::from_u64)?;
3393 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3394 let offset = input.offset_from(parameters.section);
3395 input.skip(length)?;
3396 Ok(CallFrameInstruction::Expression {
3397 register,
3398 expression: UnwindExpression { offset, length },
3399 })
3400 }
3401
3402 constants::DW_CFA_offset_extended_sf => {
3403 let register = input.read_uleb128().and_then(Register::from_u64)?;
3404 let offset = input.read_sleb128()?;
3405 Ok(CallFrameInstruction::OffsetExtendedSf {
3406 register,
3407 factored_offset: offset,
3408 })
3409 }
3410
3411 constants::DW_CFA_def_cfa_sf => {
3412 let register = input.read_uleb128().and_then(Register::from_u64)?;
3413 let offset = input.read_sleb128()?;
3414 Ok(CallFrameInstruction::DefCfaSf {
3415 register,
3416 factored_offset: offset,
3417 })
3418 }
3419
3420 constants::DW_CFA_def_cfa_offset_sf => {
3421 let offset = input.read_sleb128()?;
3422 Ok(CallFrameInstruction::DefCfaOffsetSf {
3423 factored_offset: offset,
3424 })
3425 }
3426
3427 constants::DW_CFA_val_offset => {
3428 let register = input.read_uleb128().and_then(Register::from_u64)?;
3429 let offset = input.read_uleb128()?;
3430 Ok(CallFrameInstruction::ValOffset {
3431 register,
3432 factored_offset: offset,
3433 })
3434 }
3435
3436 constants::DW_CFA_val_offset_sf => {
3437 let register = input.read_uleb128().and_then(Register::from_u64)?;
3438 let offset = input.read_sleb128()?;
3439 Ok(CallFrameInstruction::ValOffsetSf {
3440 register,
3441 factored_offset: offset,
3442 })
3443 }
3444
3445 constants::DW_CFA_val_expression => {
3446 let register = input.read_uleb128().and_then(Register::from_u64)?;
3447 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3448 let offset = input.offset_from(parameters.section);
3449 input.skip(length)?;
3450 Ok(CallFrameInstruction::ValExpression {
3451 register,
3452 expression: UnwindExpression { offset, length },
3453 })
3454 }
3455
3456 constants::DW_CFA_GNU_args_size => {
3457 let size = input.read_uleb128()?;
3458 Ok(CallFrameInstruction::ArgsSize { size })
3459 }
3460
3461 constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => {
3462 Ok(CallFrameInstruction::NegateRaState)
3463 }
3464
3465 otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
3466 }
3467 }
3468}
3469
3470#[derive(Clone, Debug)]
3475pub struct CallFrameInstructionIter<'a, R: Reader> {
3476 input: R,
3477 address_encoding: Option<constants::DwEhPe>,
3478 parameters: PointerEncodingParameters<'a, R>,
3479 vendor: Vendor,
3480}
3481
3482impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
3483 pub fn next(&mut self) -> Result<Option<CallFrameInstruction<R::Offset>>> {
3485 if self.input.is_empty() {
3486 return Ok(None);
3487 }
3488
3489 match CallFrameInstruction::parse(
3490 &mut self.input,
3491 self.address_encoding,
3492 &self.parameters,
3493 self.vendor,
3494 ) {
3495 Ok(instruction) => Ok(Some(instruction)),
3496 Err(e) => {
3497 self.input.empty();
3498 Err(e)
3499 }
3500 }
3501 }
3502}
3503
3504#[cfg(feature = "fallible-iterator")]
3505impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> {
3506 type Item = CallFrameInstruction<R::Offset>;
3507 type Error = Error;
3508
3509 fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
3510 CallFrameInstructionIter::next(self)
3511 }
3512}
3513
3514#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3541pub struct UnwindExpression<T: ReaderOffset> {
3542 pub offset: T,
3544 pub length: T,
3546}
3547
3548impl<T: ReaderOffset> UnwindExpression<T> {
3549 pub fn get<R, S>(&self, section: &S) -> Result<Expression<R>>
3554 where
3555 R: Reader<Offset = T>,
3556 S: UnwindSection<R>,
3557 {
3558 let input = &mut section.section().clone();
3559 input.skip(self.offset)?;
3560 let data = input.split(self.length)?;
3561 Ok(Expression(data))
3562 }
3563}
3564
3565#[doc(hidden)]
3567#[inline]
3568fn parse_pointer_encoding<R: Reader>(input: &mut R) -> Result<constants::DwEhPe> {
3569 let eh_pe = input.read_u8()?;
3570 let eh_pe = constants::DwEhPe(eh_pe);
3571
3572 if eh_pe.is_valid_encoding() {
3573 Ok(eh_pe)
3574 } else {
3575 Err(Error::UnknownPointerEncoding(eh_pe))
3576 }
3577}
3578
3579#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3581pub enum Pointer {
3582 Direct(u64),
3584
3585 Indirect(u64),
3592}
3593
3594impl Default for Pointer {
3595 #[inline]
3596 fn default() -> Self {
3597 Pointer::Direct(0)
3598 }
3599}
3600
3601impl Pointer {
3602 #[inline]
3603 fn new(encoding: constants::DwEhPe, address: u64) -> Pointer {
3604 if encoding.is_indirect() {
3605 Pointer::Indirect(address)
3606 } else {
3607 Pointer::Direct(address)
3608 }
3609 }
3610
3611 #[inline]
3613 pub fn direct(self) -> Result<u64> {
3614 match self {
3615 Pointer::Direct(p) => Ok(p),
3616 Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding),
3617 }
3618 }
3619
3620 #[inline]
3622 pub fn pointer(self) -> u64 {
3623 match self {
3624 Pointer::Direct(p) | Pointer::Indirect(p) => p,
3625 }
3626 }
3627}
3628
3629#[derive(Clone, Debug)]
3630struct PointerEncodingParameters<'a, R: Reader> {
3631 bases: &'a SectionBaseAddresses,
3632 func_base: Option<u64>,
3633 address_size: u8,
3634 section: &'a R,
3635}
3636
3637fn parse_encoded_pointer<R: Reader>(
3638 encoding: constants::DwEhPe,
3639 parameters: &PointerEncodingParameters<'_, R>,
3640 input: &mut R,
3641) -> Result<Pointer> {
3642 if !encoding.is_valid_encoding() {
3644 return Err(Error::UnknownPointerEncoding(encoding));
3645 }
3646
3647 if encoding == constants::DW_EH_PE_omit {
3648 return Err(Error::CannotParseOmitPointerEncoding);
3649 }
3650
3651 let base = match encoding.application() {
3652 constants::DW_EH_PE_absptr => 0,
3653 constants::DW_EH_PE_pcrel => {
3654 if let Some(section_base) = parameters.bases.section {
3655 let offset_from_section = input.offset_from(parameters.section);
3656 section_base
3657 .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size)
3658 } else {
3659 return Err(Error::PcRelativePointerButSectionBaseIsUndefined);
3660 }
3661 }
3662 constants::DW_EH_PE_textrel => {
3663 if let Some(text) = parameters.bases.text {
3664 text
3665 } else {
3666 return Err(Error::TextRelativePointerButTextBaseIsUndefined);
3667 }
3668 }
3669 constants::DW_EH_PE_datarel => {
3670 if let Some(data) = parameters.bases.data {
3671 data
3672 } else {
3673 return Err(Error::DataRelativePointerButDataBaseIsUndefined);
3674 }
3675 }
3676 constants::DW_EH_PE_funcrel => {
3677 if let Some(func) = parameters.func_base {
3678 func
3679 } else {
3680 return Err(Error::FuncRelativePointerInBadContext);
3681 }
3682 }
3683 constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding),
3684 _ => unreachable!(),
3685 };
3686
3687 let offset = parse_encoded_value(encoding, parameters, input)?;
3688 Ok(Pointer::new(
3689 encoding,
3690 base.wrapping_add_sized(offset, parameters.address_size),
3691 ))
3692}
3693
3694fn parse_encoded_value<R: Reader>(
3695 encoding: constants::DwEhPe,
3696 parameters: &PointerEncodingParameters<'_, R>,
3697 input: &mut R,
3698) -> Result<u64> {
3699 match encoding.format() {
3700 constants::DW_EH_PE_absptr => input.read_address(parameters.address_size),
3702 constants::DW_EH_PE_uleb128 => input.read_uleb128(),
3703 constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from),
3704 constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from),
3705 constants::DW_EH_PE_udata8 => input.read_u64(),
3706
3707 constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64),
3712 constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64),
3713 constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64),
3714 constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64),
3715
3716 _ => unreachable!(),
3718 }
3719}
3720
3721#[cfg(test)]
3722mod tests {
3723 use super::*;
3724 use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext};
3725 use crate::common::Format;
3726 use crate::constants;
3727 use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian};
3728 use crate::read::{
3729 EndianSlice, Error, Pointer, ReaderOffsetId, Result, Section as ReadSection,
3730 };
3731 use crate::test_util::GimliSectionMethods;
3732 use alloc::boxed::Box;
3733 use alloc::vec::Vec;
3734 use core::marker::PhantomData;
3735 use core::mem;
3736 use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum};
3737
3738 #[derive(Clone, Copy)]
3740 struct SectionKind<Section>(PhantomData<Section>);
3741
3742 impl<T> SectionKind<T> {
3743 fn endian<'input, E>(self) -> Endian
3744 where
3745 E: Endianity,
3746 T: UnwindSection<EndianSlice<'input, E>>,
3747 T::Offset: UnwindOffset<usize>,
3748 {
3749 if E::default().is_big_endian() {
3750 Endian::Big
3751 } else {
3752 Endian::Little
3753 }
3754 }
3755
3756 fn section<'input, E>(self, contents: &'input [u8]) -> T
3757 where
3758 E: Endianity,
3759 T: UnwindSection<EndianSlice<'input, E>> + ReadSection<EndianSlice<'input, E>>,
3760 T::Offset: UnwindOffset<usize>,
3761 {
3762 EndianSlice::new(contents, E::default()).into()
3763 }
3764 }
3765
3766 fn debug_frame_le<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, LittleEndian>>> {
3767 SectionKind(PhantomData)
3768 }
3769
3770 fn debug_frame_be<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, BigEndian>>> {
3771 SectionKind(PhantomData)
3772 }
3773
3774 fn eh_frame_le<'a>() -> SectionKind<EhFrame<EndianSlice<'a, LittleEndian>>> {
3775 SectionKind(PhantomData)
3776 }
3777
3778 fn parse_fde<Section, O, F, R>(
3779 section: Section,
3780 input: &mut R,
3781 get_cie: F,
3782 ) -> Result<FrameDescriptionEntry<R>>
3783 where
3784 R: Reader,
3785 Section: UnwindSection<R, Offset = O>,
3786 O: UnwindOffset<R::Offset>,
3787 F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>,
3788 {
3789 let bases = Default::default();
3790 match parse_cfi_entry(&bases, §ion, input) {
3791 Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie),
3792 Ok(_) => Err(Error::NoEntryAtGivenOffset),
3793 Err(e) => Err(e),
3794 }
3795 }
3796
3797 trait CfiSectionMethods: GimliSectionMethods {
3800 fn cie<'aug, 'input, E, T>(
3801 self,
3802 _kind: SectionKind<T>,
3803 augmentation: Option<&'aug str>,
3804 cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3805 ) -> Self
3806 where
3807 E: Endianity,
3808 T: UnwindSection<EndianSlice<'input, E>>,
3809 T::Offset: UnwindOffset;
3810 fn fde<'a, 'input, E, T, L>(
3811 self,
3812 _kind: SectionKind<T>,
3813 cie_offset: L,
3814 fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3815 ) -> Self
3816 where
3817 E: Endianity,
3818 T: UnwindSection<EndianSlice<'input, E>>,
3819 T::Offset: UnwindOffset,
3820 L: ToLabelOrNum<'a, u64>;
3821 }
3822
3823 impl CfiSectionMethods for Section {
3824 fn cie<'aug, 'input, E, T>(
3825 self,
3826 _kind: SectionKind<T>,
3827 augmentation: Option<&'aug str>,
3828 cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3829 ) -> Self
3830 where
3831 E: Endianity,
3832 T: UnwindSection<EndianSlice<'input, E>>,
3833 T::Offset: UnwindOffset,
3834 {
3835 cie.offset = self.size() as _;
3836 let length = Label::new();
3837 let start = Label::new();
3838 let end = Label::new();
3839
3840 let section = match cie.format {
3841 Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff),
3842 Format::Dwarf64 => {
3843 let section = self.D32(0xffff_ffff);
3844 section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff)
3845 }
3846 };
3847
3848 let mut section = section.D8(cie.version);
3849
3850 if let Some(augmentation) = augmentation {
3851 section = section.append_bytes(augmentation.as_bytes());
3852 }
3853
3854 let section = section.D8(0);
3856
3857 let section = if T::has_address_and_segment_sizes(cie.version) {
3858 section.D8(cie.address_size).D8(0)
3859 } else {
3860 section
3861 };
3862
3863 let section = section
3864 .uleb(cie.code_alignment_factor)
3865 .sleb(cie.data_alignment_factor)
3866 .uleb(cie.return_address_register.0.into())
3867 .append_bytes(cie.initial_instructions.slice())
3868 .mark(&end);
3869
3870 cie.length = (&end - &start) as usize;
3871 length.set_const(cie.length as u64);
3872
3873 section
3874 }
3875
3876 fn fde<'a, 'input, E, T, L>(
3877 self,
3878 _kind: SectionKind<T>,
3879 cie_offset: L,
3880 fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3881 ) -> Self
3882 where
3883 E: Endianity,
3884 T: UnwindSection<EndianSlice<'input, E>>,
3885 T::Offset: UnwindOffset,
3886 L: ToLabelOrNum<'a, u64>,
3887 {
3888 fde.offset = self.size() as _;
3889 let length = Label::new();
3890 let start = Label::new();
3891 let end = Label::new();
3892
3893 assert_eq!(fde.format, fde.cie.format);
3894
3895 let section = match T::cie_offset_encoding(fde.format) {
3896 CieOffsetEncoding::U32 => {
3897 let section = self.D32(&length).mark(&start);
3898 match cie_offset.to_labelornum() {
3899 LabelOrNum::Label(ref l) => section.D32(l),
3900 LabelOrNum::Num(o) => section.D32(o as u32),
3901 }
3902 }
3903 CieOffsetEncoding::U64 => {
3904 let section = self.D32(0xffff_ffff);
3905 section.D64(&length).mark(&start).D64(cie_offset)
3906 }
3907 };
3908
3909 let section = match fde.cie.address_size {
3910 4 => section
3911 .D32(fde.initial_address() as u32)
3912 .D32(fde.len() as u32),
3913 8 => section.D64(fde.initial_address()).D64(fde.len()),
3914 x => panic!("Unsupported address size: {}", x),
3915 };
3916
3917 let section = if let Some(ref augmentation) = fde.augmentation {
3918 let cie_aug = fde
3919 .cie
3920 .augmentation
3921 .expect("FDE has augmentation, but CIE doesn't");
3922
3923 if let Some(lsda) = augmentation.lsda {
3924 assert_eq!(
3926 cie_aug
3927 .lsda
3928 .expect("FDE has lsda, but CIE doesn't")
3929 .format(),
3930 constants::DW_EH_PE_absptr
3931 );
3932
3933 let section = section.uleb(u64::from(fde.cie.address_size));
3935 match fde.cie.address_size {
3936 4 => section.D32({
3937 let x: u64 = lsda.pointer();
3938 x as u32
3939 }),
3940 8 => section.D64({
3941 let x: u64 = lsda.pointer();
3942 x
3943 }),
3944 x => panic!("Unsupported address size: {}", x),
3945 }
3946 } else {
3947 section.uleb(0)
3950 }
3951 } else {
3952 section
3953 };
3954
3955 let section = section.append_bytes(fde.instructions.slice()).mark(&end);
3956
3957 fde.length = (&end - &start) as usize;
3958 length.set_const(fde.length as u64);
3959
3960 section
3961 }
3962 }
3963
3964 trait ResultExt {
3965 fn map_eof(self, input: &[u8]) -> Self;
3966 }
3967
3968 impl<T> ResultExt for Result<T> {
3969 fn map_eof(self, input: &[u8]) -> Self {
3970 match self {
3971 Err(Error::UnexpectedEof(id)) => {
3972 let id = ReaderOffsetId(id.0 - input.as_ptr() as u64);
3973 Err(Error::UnexpectedEof(id))
3974 }
3975 r => r,
3976 }
3977 }
3978 }
3979
3980 fn assert_parse_cie<'input, E>(
3981 kind: SectionKind<DebugFrame<EndianSlice<'input, E>>>,
3982 section: Section,
3983 address_size: u8,
3984 expected: Result<(
3985 EndianSlice<'input, E>,
3986 CommonInformationEntry<EndianSlice<'input, E>>,
3987 )>,
3988 ) where
3989 E: Endianity,
3990 {
3991 let section = section.get_contents().unwrap();
3992 let mut debug_frame = kind.section(§ion);
3993 debug_frame.set_address_size(address_size);
3994 let input = &mut EndianSlice::new(§ion, E::default());
3995 let bases = Default::default();
3996 let result = CommonInformationEntry::parse(&bases, &debug_frame, input);
3997 let result = result.map(|cie| (*input, cie)).map_eof(§ion);
3998 assert_eq!(result, expected);
3999 }
4000
4001 #[test]
4002 fn test_parse_cie_incomplete_length_32() {
4003 let kind = debug_frame_le();
4004 let section = Section::with_endian(kind.endian()).L16(5);
4005 assert_parse_cie(
4006 kind,
4007 section,
4008 8,
4009 Err(Error::UnexpectedEof(ReaderOffsetId(0))),
4010 );
4011 }
4012
4013 #[test]
4014 fn test_parse_cie_incomplete_length_64() {
4015 let kind = debug_frame_le();
4016 let section = Section::with_endian(kind.endian())
4017 .L32(0xffff_ffff)
4018 .L32(12345);
4019 assert_parse_cie(
4020 kind,
4021 section,
4022 8,
4023 Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4024 );
4025 }
4026
4027 #[test]
4028 fn test_parse_cie_incomplete_id_32() {
4029 let kind = debug_frame_be();
4030 let section = Section::with_endian(kind.endian())
4031 .B32(3)
4033 .B32(0xffff_ffff);
4034 assert_parse_cie(
4035 kind,
4036 section,
4037 8,
4038 Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4039 );
4040 }
4041
4042 #[test]
4043 fn test_parse_cie_bad_id_32() {
4044 let kind = debug_frame_be();
4045 let section = Section::with_endian(kind.endian())
4046 .B32(4)
4048 .B32(0xbad1_bad2);
4050 assert_parse_cie(kind, section, 8, Err(Error::NotCieId));
4051 }
4052
4053 #[test]
4054 fn test_parse_cie_32_bad_version() {
4055 let mut cie = CommonInformationEntry {
4056 offset: 0,
4057 length: 0,
4058 format: Format::Dwarf32,
4059 version: 99,
4060 augmentation: None,
4061 address_size: 4,
4062 code_alignment_factor: 1,
4063 data_alignment_factor: 2,
4064 return_address_register: Register(3),
4065 initial_instructions: EndianSlice::new(&[], LittleEndian),
4066 };
4067
4068 let kind = debug_frame_le();
4069 let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4070 assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99)));
4071 }
4072
4073 #[test]
4074 fn test_parse_cie_unknown_augmentation() {
4075 let length = Label::new();
4076 let start = Label::new();
4077 let end = Label::new();
4078
4079 let augmentation = "replicant";
4080 let expected_rest = [1, 2, 3];
4081
4082 let kind = debug_frame_le();
4083 let section = Section::with_endian(kind.endian())
4084 .L32(&length)
4086 .mark(&start)
4087 .L32(0xffff_ffff)
4089 .D8(4)
4091 .append_bytes(augmentation.as_bytes())
4093 .D8(0)
4095 .L32(1)
4097 .L32(2)
4098 .L32(3)
4099 .L32(4)
4100 .L32(5)
4101 .L32(6)
4102 .mark(&end)
4103 .append_bytes(&expected_rest);
4104
4105 let expected_length = (&end - &start) as u64;
4106 length.set_const(expected_length);
4107
4108 assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation));
4109 }
4110
4111 fn test_parse_cie(format: Format, version: u8, address_size: u8) {
4112 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4113 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4114
4115 let mut cie = CommonInformationEntry {
4116 offset: 0,
4117 length: 0,
4118 format,
4119 version,
4120 augmentation: None,
4121 address_size,
4122 code_alignment_factor: 16,
4123 data_alignment_factor: 32,
4124 return_address_register: Register(1),
4125 initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4126 };
4127
4128 let kind = debug_frame_le();
4129 let section = Section::with_endian(kind.endian())
4130 .cie(kind, None, &mut cie)
4131 .append_bytes(&expected_rest);
4132
4133 assert_parse_cie(
4134 kind,
4135 section,
4136 address_size,
4137 Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)),
4138 );
4139 }
4140
4141 #[test]
4142 fn test_parse_cie_32_ok() {
4143 test_parse_cie(Format::Dwarf32, 1, 4);
4144 test_parse_cie(Format::Dwarf32, 1, 8);
4145 test_parse_cie(Format::Dwarf32, 4, 4);
4146 test_parse_cie(Format::Dwarf32, 4, 8);
4147 }
4148
4149 #[test]
4150 fn test_parse_cie_64_ok() {
4151 test_parse_cie(Format::Dwarf64, 1, 4);
4152 test_parse_cie(Format::Dwarf64, 1, 8);
4153 test_parse_cie(Format::Dwarf64, 4, 4);
4154 test_parse_cie(Format::Dwarf64, 4, 8);
4155 }
4156
4157 #[test]
4158 fn test_parse_cie_length_too_big() {
4159 let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect();
4160
4161 let mut cie = CommonInformationEntry {
4162 offset: 0,
4163 length: 0,
4164 format: Format::Dwarf32,
4165 version: 4,
4166 augmentation: None,
4167 address_size: 4,
4168 code_alignment_factor: 0,
4169 data_alignment_factor: 0,
4170 return_address_register: Register(3),
4171 initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4172 };
4173
4174 let kind = debug_frame_le();
4175 let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4176
4177 let mut contents = section.get_contents().unwrap();
4178
4179 contents[0] = 0;
4181 contents[1] = 0;
4182 contents[2] = 0;
4183 contents[3] = 255;
4184
4185 let debug_frame = DebugFrame::new(&contents, LittleEndian);
4186 let bases = Default::default();
4187 assert_eq!(
4188 CommonInformationEntry::parse(
4189 &bases,
4190 &debug_frame,
4191 &mut EndianSlice::new(&contents, LittleEndian)
4192 )
4193 .map_eof(&contents),
4194 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4195 );
4196 }
4197
4198 #[test]
4199 fn test_parse_fde_incomplete_length_32() {
4200 let kind = debug_frame_le();
4201 let section = Section::with_endian(kind.endian()).L16(5);
4202 let section = section.get_contents().unwrap();
4203 let debug_frame = kind.section(§ion);
4204 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4205 assert_eq!(
4206 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4207 Err(Error::UnexpectedEof(ReaderOffsetId(0)))
4208 );
4209 }
4210
4211 #[test]
4212 fn test_parse_fde_incomplete_length_64() {
4213 let kind = debug_frame_le();
4214 let section = Section::with_endian(kind.endian())
4215 .L32(0xffff_ffff)
4216 .L32(12345);
4217 let section = section.get_contents().unwrap();
4218 let debug_frame = kind.section(§ion);
4219 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4220 assert_eq!(
4221 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4222 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4223 );
4224 }
4225
4226 #[test]
4227 fn test_parse_fde_incomplete_cie_pointer_32() {
4228 let kind = debug_frame_be();
4229 let section = Section::with_endian(kind.endian())
4230 .B32(3)
4232 .B32(1994);
4233 let section = section.get_contents().unwrap();
4234 let debug_frame = kind.section(§ion);
4235 let rest = &mut EndianSlice::new(§ion, BigEndian);
4236 assert_eq!(
4237 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4238 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4239 );
4240 }
4241
4242 #[test]
4243 fn test_parse_fde_32_ok() {
4244 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4245 let cie_offset = 0xbad0_bad1;
4246 let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4247
4248 let cie = CommonInformationEntry {
4249 offset: 0,
4250 length: 100,
4251 format: Format::Dwarf32,
4252 version: 4,
4253 augmentation: None,
4254 address_size: 8,
4256 code_alignment_factor: 3,
4257 data_alignment_factor: 2,
4258 return_address_register: Register(1),
4259 initial_instructions: EndianSlice::new(&[], LittleEndian),
4260 };
4261
4262 let mut fde = FrameDescriptionEntry {
4263 offset: 0,
4264 length: 0,
4265 format: Format::Dwarf32,
4266 cie: cie.clone(),
4267 initial_address: 0xfeed_beef,
4268 address_range: 39,
4269 augmentation: None,
4270 instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4271 };
4272
4273 let kind = debug_frame_le();
4274 let section = Section::with_endian(kind.endian())
4275 .fde(kind, cie_offset, &mut fde)
4276 .append_bytes(&expected_rest);
4277
4278 let section = section.get_contents().unwrap();
4279 let debug_frame = kind.section(§ion);
4280 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4281
4282 let get_cie = |_: &_, _: &_, offset| {
4283 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4284 Ok(cie.clone())
4285 };
4286
4287 assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4288 assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4289 }
4290
4291 #[test]
4292 fn test_parse_fde_64_ok() {
4293 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4294 let cie_offset = 0xbad0_bad1;
4295 let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4296
4297 let cie = CommonInformationEntry {
4298 offset: 0,
4299 length: 100,
4300 format: Format::Dwarf64,
4301 version: 4,
4302 augmentation: None,
4303 address_size: 8,
4304 code_alignment_factor: 3,
4305 data_alignment_factor: 2,
4306 return_address_register: Register(1),
4307 initial_instructions: EndianSlice::new(&[], LittleEndian),
4308 };
4309
4310 let mut fde = FrameDescriptionEntry {
4311 offset: 0,
4312 length: 0,
4313 format: Format::Dwarf64,
4314 cie: cie.clone(),
4315 initial_address: 0xfeed_beef,
4316 address_range: 999,
4317 augmentation: None,
4318 instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4319 };
4320
4321 let kind = debug_frame_le();
4322 let section = Section::with_endian(kind.endian())
4323 .fde(kind, cie_offset, &mut fde)
4324 .append_bytes(&expected_rest);
4325
4326 let section = section.get_contents().unwrap();
4327 let debug_frame = kind.section(§ion);
4328 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4329
4330 let get_cie = |_: &_, _: &_, offset| {
4331 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4332 Ok(cie.clone())
4333 };
4334
4335 assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4336 assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4337 }
4338
4339 #[test]
4340 fn test_parse_cfi_entry_on_cie_32_ok() {
4341 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4342 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4343
4344 let mut cie = CommonInformationEntry {
4345 offset: 0,
4346 length: 0,
4347 format: Format::Dwarf32,
4348 version: 4,
4349 augmentation: None,
4350 address_size: 4,
4351 code_alignment_factor: 16,
4352 data_alignment_factor: 32,
4353 return_address_register: Register(1),
4354 initial_instructions: EndianSlice::new(&expected_instrs, BigEndian),
4355 };
4356
4357 let kind = debug_frame_be();
4358 let section = Section::with_endian(kind.endian())
4359 .cie(kind, None, &mut cie)
4360 .append_bytes(&expected_rest);
4361 let section = section.get_contents().unwrap();
4362 let debug_frame = kind.section(§ion);
4363 let rest = &mut EndianSlice::new(§ion, BigEndian);
4364
4365 let bases = Default::default();
4366 assert_eq!(
4367 parse_cfi_entry(&bases, &debug_frame, rest),
4368 Ok(Some(CieOrFde::Cie(cie)))
4369 );
4370 assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4371 }
4372
4373 #[test]
4374 fn test_parse_cfi_entry_on_fde_32_ok() {
4375 let cie_offset = 0x1234_5678;
4376 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4377 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4378
4379 let cie = CommonInformationEntry {
4380 offset: 0,
4381 length: 0,
4382 format: Format::Dwarf32,
4383 version: 4,
4384 augmentation: None,
4385 address_size: 4,
4386 code_alignment_factor: 16,
4387 data_alignment_factor: 32,
4388 return_address_register: Register(1),
4389 initial_instructions: EndianSlice::new(&[], BigEndian),
4390 };
4391
4392 let mut fde = FrameDescriptionEntry {
4393 offset: 0,
4394 length: 0,
4395 format: Format::Dwarf32,
4396 cie: cie.clone(),
4397 initial_address: 0xfeed_beef,
4398 address_range: 39,
4399 augmentation: None,
4400 instructions: EndianSlice::new(&expected_instrs, BigEndian),
4401 };
4402
4403 let kind = debug_frame_be();
4404 let section = Section::with_endian(kind.endian())
4405 .fde(kind, cie_offset, &mut fde)
4406 .append_bytes(&expected_rest);
4407
4408 let section = section.get_contents().unwrap();
4409 let debug_frame = kind.section(§ion);
4410 let rest = &mut EndianSlice::new(§ion, BigEndian);
4411
4412 let bases = Default::default();
4413 match parse_cfi_entry(&bases, &debug_frame, rest) {
4414 Ok(Some(CieOrFde::Fde(partial))) => {
4415 assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4416
4417 assert_eq!(partial.length, fde.length);
4418 assert_eq!(partial.format, fde.format);
4419 assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize));
4420
4421 let get_cie = |_: &_, _: &_, offset| {
4422 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4423 Ok(cie.clone())
4424 };
4425
4426 assert_eq!(partial.parse(get_cie), Ok(fde));
4427 }
4428 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4429 }
4430 }
4431
4432 #[test]
4433 fn test_cfi_entries_iter() {
4434 let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4435
4436 let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
4437
4438 let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect();
4439
4440 let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
4441
4442 let mut cie1 = CommonInformationEntry {
4443 offset: 0,
4444 length: 0,
4445 format: Format::Dwarf32,
4446 version: 4,
4447 augmentation: None,
4448 address_size: 4,
4449 code_alignment_factor: 1,
4450 data_alignment_factor: 2,
4451 return_address_register: Register(3),
4452 initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian),
4453 };
4454
4455 let mut cie2 = CommonInformationEntry {
4456 offset: 0,
4457 length: 0,
4458 format: Format::Dwarf32,
4459 version: 4,
4460 augmentation: None,
4461 address_size: 4,
4462 code_alignment_factor: 3,
4463 data_alignment_factor: 2,
4464 return_address_register: Register(1),
4465 initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian),
4466 };
4467
4468 let cie1_location = Label::new();
4469 let cie2_location = Label::new();
4470
4471 let kind = debug_frame_be();
4475 let section = Section::with_endian(kind.endian())
4476 .mark(&cie1_location)
4477 .cie(kind, None, &mut cie1)
4478 .mark(&cie2_location)
4479 .cie(kind, None, &mut cie2);
4480
4481 let mut fde1 = FrameDescriptionEntry {
4482 offset: 0,
4483 length: 0,
4484 format: Format::Dwarf32,
4485 cie: cie1.clone(),
4486 initial_address: 0xfeed_beef,
4487 address_range: 39,
4488 augmentation: None,
4489 instructions: EndianSlice::new(&expected_instrs3, BigEndian),
4490 };
4491
4492 let mut fde2 = FrameDescriptionEntry {
4493 offset: 0,
4494 length: 0,
4495 format: Format::Dwarf32,
4496 cie: cie2.clone(),
4497 initial_address: 0xfeed_face,
4498 address_range: 9000,
4499 augmentation: None,
4500 instructions: EndianSlice::new(&expected_instrs4, BigEndian),
4501 };
4502
4503 let section =
4504 section
4505 .fde(kind, &cie1_location, &mut fde1)
4506 .fde(kind, &cie2_location, &mut fde2);
4507
4508 section.start().set_const(0);
4509
4510 let cie1_offset = cie1_location.value().unwrap() as usize;
4511 let cie2_offset = cie2_location.value().unwrap() as usize;
4512
4513 let contents = section.get_contents().unwrap();
4514 let debug_frame = kind.section(&contents);
4515
4516 let bases = Default::default();
4517 let mut entries = debug_frame.entries(&bases);
4518
4519 assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone()))));
4520 assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone()))));
4521
4522 match entries.next() {
4523 Ok(Some(CieOrFde::Fde(partial))) => {
4524 assert_eq!(partial.length, fde1.length);
4525 assert_eq!(partial.format, fde1.format);
4526 assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset));
4527
4528 let get_cie = |_: &_, _: &_, offset| {
4529 assert_eq!(offset, DebugFrameOffset(cie1_offset));
4530 Ok(cie1.clone())
4531 };
4532 assert_eq!(partial.parse(get_cie), Ok(fde1));
4533 }
4534 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4535 }
4536
4537 match entries.next() {
4538 Ok(Some(CieOrFde::Fde(partial))) => {
4539 assert_eq!(partial.length, fde2.length);
4540 assert_eq!(partial.format, fde2.format);
4541 assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset));
4542
4543 let get_cie = |_: &_, _: &_, offset| {
4544 assert_eq!(offset, DebugFrameOffset(cie2_offset));
4545 Ok(cie2.clone())
4546 };
4547 assert_eq!(partial.parse(get_cie), Ok(fde2));
4548 }
4549 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4550 }
4551
4552 assert_eq!(entries.next(), Ok(None));
4553 }
4554
4555 #[test]
4556 fn test_parse_cie_from_offset() {
4557 let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4558 let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect();
4559
4560 let mut cie = CommonInformationEntry {
4561 offset: 0,
4562 length: 0,
4563 format: Format::Dwarf64,
4564 version: 4,
4565 augmentation: None,
4566 address_size: 4,
4567 code_alignment_factor: 4,
4568 data_alignment_factor: 8,
4569 return_address_register: Register(12),
4570 initial_instructions: EndianSlice::new(&instrs, LittleEndian),
4571 };
4572
4573 let cie_location = Label::new();
4574
4575 let kind = debug_frame_le();
4576 let section = Section::with_endian(kind.endian())
4577 .append_bytes(&filler)
4578 .mark(&cie_location)
4579 .cie(kind, None, &mut cie)
4580 .append_bytes(&filler);
4581
4582 section.start().set_const(0);
4583
4584 let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize);
4585
4586 let contents = section.get_contents().unwrap();
4587 let debug_frame = kind.section(&contents);
4588 let bases = Default::default();
4589
4590 assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie));
4591 }
4592
4593 fn parse_cfi_instruction<R: Reader + Default>(
4594 input: &mut R,
4595 address_size: u8,
4596 ) -> Result<CallFrameInstruction<R::Offset>> {
4597 let section = input.clone();
4598 let parameters = &PointerEncodingParameters {
4599 bases: &SectionBaseAddresses::default(),
4600 func_base: None,
4601 address_size,
4602 section: §ion,
4603 };
4604 CallFrameInstruction::parse(input, None, parameters, Vendor::Default)
4605 }
4606
4607 #[test]
4608 fn test_parse_cfi_instruction_advance_loc() {
4609 let expected_rest = [1, 2, 3, 4];
4610 let expected_delta = 42;
4611 let section = Section::with_endian(Endian::Little)
4612 .D8(constants::DW_CFA_advance_loc.0 | expected_delta)
4613 .append_bytes(&expected_rest);
4614 let contents = section.get_contents().unwrap();
4615 let input = &mut EndianSlice::new(&contents, LittleEndian);
4616 assert_eq!(
4617 parse_cfi_instruction(input, 8),
4618 Ok(CallFrameInstruction::AdvanceLoc {
4619 delta: u32::from(expected_delta),
4620 })
4621 );
4622 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4623 }
4624
4625 #[test]
4626 fn test_parse_cfi_instruction_offset() {
4627 let expected_rest = [1, 2, 3, 4];
4628 let expected_reg = 3;
4629 let expected_offset = 1997;
4630 let section = Section::with_endian(Endian::Little)
4631 .D8(constants::DW_CFA_offset.0 | expected_reg)
4632 .uleb(expected_offset)
4633 .append_bytes(&expected_rest);
4634 let contents = section.get_contents().unwrap();
4635 let input = &mut EndianSlice::new(&contents, LittleEndian);
4636 assert_eq!(
4637 parse_cfi_instruction(input, 8),
4638 Ok(CallFrameInstruction::Offset {
4639 register: Register(expected_reg.into()),
4640 factored_offset: expected_offset,
4641 })
4642 );
4643 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4644 }
4645
4646 #[test]
4647 fn test_parse_cfi_instruction_restore() {
4648 let expected_rest = [1, 2, 3, 4];
4649 let expected_reg = 3;
4650 let section = Section::with_endian(Endian::Little)
4651 .D8(constants::DW_CFA_restore.0 | expected_reg)
4652 .append_bytes(&expected_rest);
4653 let contents = section.get_contents().unwrap();
4654 let input = &mut EndianSlice::new(&contents, LittleEndian);
4655 assert_eq!(
4656 parse_cfi_instruction(input, 8),
4657 Ok(CallFrameInstruction::Restore {
4658 register: Register(expected_reg.into()),
4659 })
4660 );
4661 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4662 }
4663
4664 #[test]
4665 fn test_parse_cfi_instruction_nop() {
4666 let expected_rest = [1, 2, 3, 4];
4667 let section = Section::with_endian(Endian::Little)
4668 .D8(constants::DW_CFA_nop.0)
4669 .append_bytes(&expected_rest);
4670 let contents = section.get_contents().unwrap();
4671 let input = &mut EndianSlice::new(&contents, LittleEndian);
4672 assert_eq!(
4673 parse_cfi_instruction(input, 8),
4674 Ok(CallFrameInstruction::Nop)
4675 );
4676 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4677 }
4678
4679 #[test]
4680 fn test_parse_cfi_instruction_set_loc() {
4681 let expected_rest = [1, 2, 3, 4];
4682 let expected_addr = 0xdead_beef;
4683 let section = Section::with_endian(Endian::Little)
4684 .D8(constants::DW_CFA_set_loc.0)
4685 .L64(expected_addr)
4686 .append_bytes(&expected_rest);
4687 let contents = section.get_contents().unwrap();
4688 let input = &mut EndianSlice::new(&contents, LittleEndian);
4689 assert_eq!(
4690 parse_cfi_instruction(input, 8),
4691 Ok(CallFrameInstruction::SetLoc {
4692 address: expected_addr,
4693 })
4694 );
4695 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4696 }
4697
4698 #[test]
4699 fn test_parse_cfi_instruction_set_loc_encoding() {
4700 let text_base = 0xfeed_face;
4701 let addr_offset = 0xbeef;
4702 let expected_addr = text_base + addr_offset;
4703 let expected_rest = [1, 2, 3, 4];
4704 let section = Section::with_endian(Endian::Little)
4705 .D8(constants::DW_CFA_set_loc.0)
4706 .L64(addr_offset)
4707 .append_bytes(&expected_rest);
4708 let contents = section.get_contents().unwrap();
4709 let input = &mut EndianSlice::new(&contents, LittleEndian);
4710 let parameters = &PointerEncodingParameters {
4711 bases: &BaseAddresses::default().set_text(text_base).eh_frame,
4712 func_base: None,
4713 address_size: 8,
4714 section: &EndianSlice::new(&[], LittleEndian),
4715 };
4716 assert_eq!(
4717 CallFrameInstruction::parse(
4718 input,
4719 Some(constants::DW_EH_PE_textrel),
4720 parameters,
4721 Vendor::Default
4722 ),
4723 Ok(CallFrameInstruction::SetLoc {
4724 address: expected_addr,
4725 })
4726 );
4727 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4728 }
4729
4730 #[test]
4731 fn test_parse_cfi_instruction_advance_loc1() {
4732 let expected_rest = [1, 2, 3, 4];
4733 let expected_delta = 8;
4734 let section = Section::with_endian(Endian::Little)
4735 .D8(constants::DW_CFA_advance_loc1.0)
4736 .D8(expected_delta)
4737 .append_bytes(&expected_rest);
4738 let contents = section.get_contents().unwrap();
4739 let input = &mut EndianSlice::new(&contents, LittleEndian);
4740 assert_eq!(
4741 parse_cfi_instruction(input, 8),
4742 Ok(CallFrameInstruction::AdvanceLoc {
4743 delta: u32::from(expected_delta),
4744 })
4745 );
4746 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4747 }
4748
4749 #[test]
4750 fn test_parse_cfi_instruction_advance_loc2() {
4751 let expected_rest = [1, 2, 3, 4];
4752 let expected_delta = 500;
4753 let section = Section::with_endian(Endian::Little)
4754 .D8(constants::DW_CFA_advance_loc2.0)
4755 .L16(expected_delta)
4756 .append_bytes(&expected_rest);
4757 let contents = section.get_contents().unwrap();
4758 let input = &mut EndianSlice::new(&contents, LittleEndian);
4759 assert_eq!(
4760 parse_cfi_instruction(input, 8),
4761 Ok(CallFrameInstruction::AdvanceLoc {
4762 delta: u32::from(expected_delta),
4763 })
4764 );
4765 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4766 }
4767
4768 #[test]
4769 fn test_parse_cfi_instruction_advance_loc4() {
4770 let expected_rest = [1, 2, 3, 4];
4771 let expected_delta = 1 << 20;
4772 let section = Section::with_endian(Endian::Little)
4773 .D8(constants::DW_CFA_advance_loc4.0)
4774 .L32(expected_delta)
4775 .append_bytes(&expected_rest);
4776 let contents = section.get_contents().unwrap();
4777 let input = &mut EndianSlice::new(&contents, LittleEndian);
4778 assert_eq!(
4779 parse_cfi_instruction(input, 8),
4780 Ok(CallFrameInstruction::AdvanceLoc {
4781 delta: expected_delta,
4782 })
4783 );
4784 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4785 }
4786
4787 #[test]
4788 fn test_parse_cfi_instruction_offset_extended() {
4789 let expected_rest = [1, 2, 3, 4];
4790 let expected_reg = 7;
4791 let expected_offset = 33;
4792 let section = Section::with_endian(Endian::Little)
4793 .D8(constants::DW_CFA_offset_extended.0)
4794 .uleb(expected_reg.into())
4795 .uleb(expected_offset)
4796 .append_bytes(&expected_rest);
4797 let contents = section.get_contents().unwrap();
4798 let input = &mut EndianSlice::new(&contents, LittleEndian);
4799 assert_eq!(
4800 parse_cfi_instruction(input, 8),
4801 Ok(CallFrameInstruction::Offset {
4802 register: Register(expected_reg),
4803 factored_offset: expected_offset,
4804 })
4805 );
4806 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4807 }
4808
4809 #[test]
4810 fn test_parse_cfi_instruction_restore_extended() {
4811 let expected_rest = [1, 2, 3, 4];
4812 let expected_reg = 7;
4813 let section = Section::with_endian(Endian::Little)
4814 .D8(constants::DW_CFA_restore_extended.0)
4815 .uleb(expected_reg.into())
4816 .append_bytes(&expected_rest);
4817 let contents = section.get_contents().unwrap();
4818 let input = &mut EndianSlice::new(&contents, LittleEndian);
4819 assert_eq!(
4820 parse_cfi_instruction(input, 8),
4821 Ok(CallFrameInstruction::Restore {
4822 register: Register(expected_reg),
4823 })
4824 );
4825 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4826 }
4827
4828 #[test]
4829 fn test_parse_cfi_instruction_undefined() {
4830 let expected_rest = [1, 2, 3, 4];
4831 let expected_reg = 7;
4832 let section = Section::with_endian(Endian::Little)
4833 .D8(constants::DW_CFA_undefined.0)
4834 .uleb(expected_reg.into())
4835 .append_bytes(&expected_rest);
4836 let contents = section.get_contents().unwrap();
4837 let input = &mut EndianSlice::new(&contents, LittleEndian);
4838 assert_eq!(
4839 parse_cfi_instruction(input, 8),
4840 Ok(CallFrameInstruction::Undefined {
4841 register: Register(expected_reg),
4842 })
4843 );
4844 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4845 }
4846
4847 #[test]
4848 fn test_parse_cfi_instruction_same_value() {
4849 let expected_rest = [1, 2, 3, 4];
4850 let expected_reg = 7;
4851 let section = Section::with_endian(Endian::Little)
4852 .D8(constants::DW_CFA_same_value.0)
4853 .uleb(expected_reg.into())
4854 .append_bytes(&expected_rest);
4855 let contents = section.get_contents().unwrap();
4856 let input = &mut EndianSlice::new(&contents, LittleEndian);
4857 assert_eq!(
4858 parse_cfi_instruction(input, 8),
4859 Ok(CallFrameInstruction::SameValue {
4860 register: Register(expected_reg),
4861 })
4862 );
4863 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4864 }
4865
4866 #[test]
4867 fn test_parse_cfi_instruction_register() {
4868 let expected_rest = [1, 2, 3, 4];
4869 let expected_dest_reg = 7;
4870 let expected_src_reg = 8;
4871 let section = Section::with_endian(Endian::Little)
4872 .D8(constants::DW_CFA_register.0)
4873 .uleb(expected_dest_reg.into())
4874 .uleb(expected_src_reg.into())
4875 .append_bytes(&expected_rest);
4876 let contents = section.get_contents().unwrap();
4877 let input = &mut EndianSlice::new(&contents, LittleEndian);
4878 assert_eq!(
4879 parse_cfi_instruction(input, 8),
4880 Ok(CallFrameInstruction::Register {
4881 dest_register: Register(expected_dest_reg),
4882 src_register: Register(expected_src_reg),
4883 })
4884 );
4885 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4886 }
4887
4888 #[test]
4889 fn test_parse_cfi_instruction_remember_state() {
4890 let expected_rest = [1, 2, 3, 4];
4891 let section = Section::with_endian(Endian::Little)
4892 .D8(constants::DW_CFA_remember_state.0)
4893 .append_bytes(&expected_rest);
4894 let contents = section.get_contents().unwrap();
4895 let input = &mut EndianSlice::new(&contents, LittleEndian);
4896 assert_eq!(
4897 parse_cfi_instruction(input, 8),
4898 Ok(CallFrameInstruction::RememberState)
4899 );
4900 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4901 }
4902
4903 #[test]
4904 fn test_parse_cfi_instruction_restore_state() {
4905 let expected_rest = [1, 2, 3, 4];
4906 let section = Section::with_endian(Endian::Little)
4907 .D8(constants::DW_CFA_restore_state.0)
4908 .append_bytes(&expected_rest);
4909 let contents = section.get_contents().unwrap();
4910 let input = &mut EndianSlice::new(&contents, LittleEndian);
4911 assert_eq!(
4912 parse_cfi_instruction(input, 8),
4913 Ok(CallFrameInstruction::RestoreState)
4914 );
4915 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4916 }
4917
4918 #[test]
4919 fn test_parse_cfi_instruction_def_cfa() {
4920 let expected_rest = [1, 2, 3, 4];
4921 let expected_reg = 2;
4922 let expected_offset = 0;
4923 let section = Section::with_endian(Endian::Little)
4924 .D8(constants::DW_CFA_def_cfa.0)
4925 .uleb(expected_reg.into())
4926 .uleb(expected_offset)
4927 .append_bytes(&expected_rest);
4928 let contents = section.get_contents().unwrap();
4929 let input = &mut EndianSlice::new(&contents, LittleEndian);
4930 assert_eq!(
4931 parse_cfi_instruction(input, 8),
4932 Ok(CallFrameInstruction::DefCfa {
4933 register: Register(expected_reg),
4934 offset: expected_offset,
4935 })
4936 );
4937 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4938 }
4939
4940 #[test]
4941 fn test_parse_cfi_instruction_def_cfa_register() {
4942 let expected_rest = [1, 2, 3, 4];
4943 let expected_reg = 2;
4944 let section = Section::with_endian(Endian::Little)
4945 .D8(constants::DW_CFA_def_cfa_register.0)
4946 .uleb(expected_reg.into())
4947 .append_bytes(&expected_rest);
4948 let contents = section.get_contents().unwrap();
4949 let input = &mut EndianSlice::new(&contents, LittleEndian);
4950 assert_eq!(
4951 parse_cfi_instruction(input, 8),
4952 Ok(CallFrameInstruction::DefCfaRegister {
4953 register: Register(expected_reg),
4954 })
4955 );
4956 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4957 }
4958
4959 #[test]
4960 fn test_parse_cfi_instruction_def_cfa_offset() {
4961 let expected_rest = [1, 2, 3, 4];
4962 let expected_offset = 23;
4963 let section = Section::with_endian(Endian::Little)
4964 .D8(constants::DW_CFA_def_cfa_offset.0)
4965 .uleb(expected_offset)
4966 .append_bytes(&expected_rest);
4967 let contents = section.get_contents().unwrap();
4968 let input = &mut EndianSlice::new(&contents, LittleEndian);
4969 assert_eq!(
4970 parse_cfi_instruction(input, 8),
4971 Ok(CallFrameInstruction::DefCfaOffset {
4972 offset: expected_offset,
4973 })
4974 );
4975 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4976 }
4977
4978 #[test]
4979 fn test_parse_cfi_instruction_def_cfa_expression() {
4980 let expected_rest = [1, 2, 3, 4];
4981 let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
4982
4983 let length = Label::new();
4984 let start = Label::new();
4985 let end = Label::new();
4986
4987 let section = Section::with_endian(Endian::Little)
4988 .D8(constants::DW_CFA_def_cfa_expression.0)
4989 .D8(&length)
4990 .mark(&start)
4991 .append_bytes(&expected_expr)
4992 .mark(&end)
4993 .append_bytes(&expected_rest);
4994
4995 length.set_const((&end - &start) as u64);
4996 let expected_expression = UnwindExpression {
4997 offset: (&start - §ion.start()) as usize,
4998 length: (&end - &start) as usize,
4999 };
5000 let contents = section.get_contents().unwrap();
5001 let input = &mut EndianSlice::new(&contents, LittleEndian);
5002
5003 assert_eq!(
5004 parse_cfi_instruction(input, 8),
5005 Ok(CallFrameInstruction::DefCfaExpression {
5006 expression: expected_expression,
5007 })
5008 );
5009 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5010 }
5011
5012 #[test]
5013 fn test_parse_cfi_instruction_expression() {
5014 let expected_rest = [1, 2, 3, 4];
5015 let expected_reg = 99;
5016 let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
5017
5018 let length = Label::new();
5019 let start = Label::new();
5020 let end = Label::new();
5021
5022 let section = Section::with_endian(Endian::Little)
5023 .D8(constants::DW_CFA_expression.0)
5024 .uleb(expected_reg.into())
5025 .D8(&length)
5026 .mark(&start)
5027 .append_bytes(&expected_expr)
5028 .mark(&end)
5029 .append_bytes(&expected_rest);
5030
5031 length.set_const((&end - &start) as u64);
5032 let expected_expression = UnwindExpression {
5033 offset: (&start - §ion.start()) as usize,
5034 length: (&end - &start) as usize,
5035 };
5036 let contents = section.get_contents().unwrap();
5037 let input = &mut EndianSlice::new(&contents, LittleEndian);
5038
5039 assert_eq!(
5040 parse_cfi_instruction(input, 8),
5041 Ok(CallFrameInstruction::Expression {
5042 register: Register(expected_reg),
5043 expression: expected_expression,
5044 })
5045 );
5046 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5047 }
5048
5049 #[test]
5050 fn test_parse_cfi_instruction_offset_extended_sf() {
5051 let expected_rest = [1, 2, 3, 4];
5052 let expected_reg = 7;
5053 let expected_offset = -33;
5054 let section = Section::with_endian(Endian::Little)
5055 .D8(constants::DW_CFA_offset_extended_sf.0)
5056 .uleb(expected_reg.into())
5057 .sleb(expected_offset)
5058 .append_bytes(&expected_rest);
5059 let contents = section.get_contents().unwrap();
5060 let input = &mut EndianSlice::new(&contents, LittleEndian);
5061 assert_eq!(
5062 parse_cfi_instruction(input, 8),
5063 Ok(CallFrameInstruction::OffsetExtendedSf {
5064 register: Register(expected_reg),
5065 factored_offset: expected_offset,
5066 })
5067 );
5068 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5069 }
5070
5071 #[test]
5072 fn test_parse_cfi_instruction_def_cfa_sf() {
5073 let expected_rest = [1, 2, 3, 4];
5074 let expected_reg = 2;
5075 let expected_offset = -9999;
5076 let section = Section::with_endian(Endian::Little)
5077 .D8(constants::DW_CFA_def_cfa_sf.0)
5078 .uleb(expected_reg.into())
5079 .sleb(expected_offset)
5080 .append_bytes(&expected_rest);
5081 let contents = section.get_contents().unwrap();
5082 let input = &mut EndianSlice::new(&contents, LittleEndian);
5083 assert_eq!(
5084 parse_cfi_instruction(input, 8),
5085 Ok(CallFrameInstruction::DefCfaSf {
5086 register: Register(expected_reg),
5087 factored_offset: expected_offset,
5088 })
5089 );
5090 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5091 }
5092
5093 #[test]
5094 fn test_parse_cfi_instruction_def_cfa_offset_sf() {
5095 let expected_rest = [1, 2, 3, 4];
5096 let expected_offset = -123;
5097 let section = Section::with_endian(Endian::Little)
5098 .D8(constants::DW_CFA_def_cfa_offset_sf.0)
5099 .sleb(expected_offset)
5100 .append_bytes(&expected_rest);
5101 let contents = section.get_contents().unwrap();
5102 let input = &mut EndianSlice::new(&contents, LittleEndian);
5103 assert_eq!(
5104 parse_cfi_instruction(input, 8),
5105 Ok(CallFrameInstruction::DefCfaOffsetSf {
5106 factored_offset: expected_offset,
5107 })
5108 );
5109 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5110 }
5111
5112 #[test]
5113 fn test_parse_cfi_instruction_val_offset() {
5114 let expected_rest = [1, 2, 3, 4];
5115 let expected_reg = 50;
5116 let expected_offset = 23;
5117 let section = Section::with_endian(Endian::Little)
5118 .D8(constants::DW_CFA_val_offset.0)
5119 .uleb(expected_reg.into())
5120 .uleb(expected_offset)
5121 .append_bytes(&expected_rest);
5122 let contents = section.get_contents().unwrap();
5123 let input = &mut EndianSlice::new(&contents, LittleEndian);
5124 assert_eq!(
5125 parse_cfi_instruction(input, 8),
5126 Ok(CallFrameInstruction::ValOffset {
5127 register: Register(expected_reg),
5128 factored_offset: expected_offset,
5129 })
5130 );
5131 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5132 }
5133
5134 #[test]
5135 fn test_parse_cfi_instruction_val_offset_sf() {
5136 let expected_rest = [1, 2, 3, 4];
5137 let expected_reg = 50;
5138 let expected_offset = -23;
5139 let section = Section::with_endian(Endian::Little)
5140 .D8(constants::DW_CFA_val_offset_sf.0)
5141 .uleb(expected_reg.into())
5142 .sleb(expected_offset)
5143 .append_bytes(&expected_rest);
5144 let contents = section.get_contents().unwrap();
5145 let input = &mut EndianSlice::new(&contents, LittleEndian);
5146 assert_eq!(
5147 parse_cfi_instruction(input, 8),
5148 Ok(CallFrameInstruction::ValOffsetSf {
5149 register: Register(expected_reg),
5150 factored_offset: expected_offset,
5151 })
5152 );
5153 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5154 }
5155
5156 #[test]
5157 fn test_parse_cfi_instruction_val_expression() {
5158 let expected_rest = [1, 2, 3, 4];
5159 let expected_reg = 50;
5160 let expected_expr = [2, 2, 1, 1, 5, 5];
5161
5162 let length = Label::new();
5163 let start = Label::new();
5164 let end = Label::new();
5165
5166 let section = Section::with_endian(Endian::Little)
5167 .D8(constants::DW_CFA_val_expression.0)
5168 .uleb(expected_reg.into())
5169 .D8(&length)
5170 .mark(&start)
5171 .append_bytes(&expected_expr)
5172 .mark(&end)
5173 .append_bytes(&expected_rest);
5174
5175 length.set_const((&end - &start) as u64);
5176 let expected_expression = UnwindExpression {
5177 offset: (&start - §ion.start()) as usize,
5178 length: (&end - &start) as usize,
5179 };
5180 let contents = section.get_contents().unwrap();
5181 let input = &mut EndianSlice::new(&contents, LittleEndian);
5182
5183 assert_eq!(
5184 parse_cfi_instruction(input, 8),
5185 Ok(CallFrameInstruction::ValExpression {
5186 register: Register(expected_reg),
5187 expression: expected_expression,
5188 })
5189 );
5190 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5191 }
5192
5193 #[test]
5194 fn test_parse_cfi_instruction_negate_ra_state() {
5195 let expected_rest = [1, 2, 3, 4];
5196 let section = Section::with_endian(Endian::Little)
5197 .D8(constants::DW_CFA_AARCH64_negate_ra_state.0)
5198 .append_bytes(&expected_rest);
5199 let contents = section.get_contents().unwrap();
5200 let input = &mut EndianSlice::new(&contents, LittleEndian);
5201 let parameters = &PointerEncodingParameters {
5202 bases: &SectionBaseAddresses::default(),
5203 func_base: None,
5204 address_size: 8,
5205 section: &EndianSlice::default(),
5206 };
5207 assert_eq!(
5208 CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64),
5209 Ok(CallFrameInstruction::NegateRaState)
5210 );
5211 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5212 }
5213
5214 #[test]
5215 fn test_parse_cfi_instruction_unknown_instruction() {
5216 let expected_rest = [1, 2, 3, 4];
5217 let unknown_instr = constants::DwCfa(0b0011_1111);
5218 let section = Section::with_endian(Endian::Little)
5219 .D8(unknown_instr.0)
5220 .append_bytes(&expected_rest);
5221 let contents = section.get_contents().unwrap();
5222 let input = &mut EndianSlice::new(&contents, LittleEndian);
5223 assert_eq!(
5224 parse_cfi_instruction(input, 8),
5225 Err(Error::UnknownCallFrameInstruction(unknown_instr))
5226 );
5227 }
5228
5229 #[test]
5230 fn test_call_frame_instruction_iter_ok() {
5231 let expected_reg = 50;
5232 let expected_expr = [2, 2, 1, 1, 5, 5];
5233 let expected_delta = 230;
5234
5235 let length = Label::new();
5236 let start = Label::new();
5237 let end = Label::new();
5238
5239 let section = Section::with_endian(Endian::Big)
5240 .D8(constants::DW_CFA_val_expression.0)
5241 .uleb(expected_reg.into())
5242 .D8(&length)
5243 .mark(&start)
5244 .append_bytes(&expected_expr)
5245 .mark(&end)
5246 .D8(constants::DW_CFA_advance_loc1.0)
5247 .D8(expected_delta);
5248
5249 length.set_const((&end - &start) as u64);
5250 let expected_expression = UnwindExpression {
5251 offset: (&start - §ion.start()) as usize,
5252 length: (&end - &start) as usize,
5253 };
5254 let contents = section.get_contents().unwrap();
5255 let input = EndianSlice::new(&contents, BigEndian);
5256 let parameters = PointerEncodingParameters {
5257 bases: &SectionBaseAddresses::default(),
5258 func_base: None,
5259 address_size: 8,
5260 section: &input,
5261 };
5262 let mut iter = CallFrameInstructionIter {
5263 input,
5264 address_encoding: None,
5265 parameters,
5266 vendor: Vendor::Default,
5267 };
5268
5269 assert_eq!(
5270 iter.next(),
5271 Ok(Some(CallFrameInstruction::ValExpression {
5272 register: Register(expected_reg),
5273 expression: expected_expression,
5274 }))
5275 );
5276
5277 assert_eq!(
5278 iter.next(),
5279 Ok(Some(CallFrameInstruction::AdvanceLoc {
5280 delta: u32::from(expected_delta),
5281 }))
5282 );
5283
5284 assert_eq!(iter.next(), Ok(None));
5285 }
5286
5287 #[test]
5288 fn test_call_frame_instruction_iter_err() {
5289 let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0);
5291
5292 let contents = section.get_contents().unwrap();
5293 let input = EndianSlice::new(&contents, BigEndian);
5294 let parameters = PointerEncodingParameters {
5295 bases: &SectionBaseAddresses::default(),
5296 func_base: None,
5297 address_size: 8,
5298 section: &EndianSlice::default(),
5299 };
5300 let mut iter = CallFrameInstructionIter {
5301 input,
5302 address_encoding: None,
5303 parameters,
5304 vendor: Vendor::Default,
5305 };
5306
5307 assert_eq!(
5308 iter.next().map_eof(&contents),
5309 Err(Error::UnexpectedEof(ReaderOffsetId(1)))
5310 );
5311 assert_eq!(iter.next(), Ok(None));
5312 }
5313
5314 fn assert_eval<'a, I>(
5315 mut initial_ctx: UnwindContext<usize>,
5316 expected_ctx: UnwindContext<usize>,
5317 cie: CommonInformationEntry<EndianSlice<'a, LittleEndian>>,
5318 fde: Option<FrameDescriptionEntry<EndianSlice<'a, LittleEndian>>>,
5319 instructions: I,
5320 ) where
5321 I: AsRef<[(Result<bool>, CallFrameInstruction<usize>)]>,
5322 {
5323 {
5324 let section = &DebugFrame::from(EndianSlice::default());
5325 let bases = &BaseAddresses::default();
5326 let mut table = match fde {
5327 Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde),
5328 None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie),
5329 };
5330 for (expected_result, instruction) in instructions.as_ref() {
5331 assert_eq!(*expected_result, table.evaluate(instruction.clone()));
5332 }
5333 }
5334
5335 assert_eq!(expected_ctx, initial_ctx);
5336 }
5337
5338 fn make_test_cie<'a>() -> CommonInformationEntry<EndianSlice<'a, LittleEndian>> {
5339 CommonInformationEntry {
5340 offset: 0,
5341 format: Format::Dwarf64,
5342 length: 0,
5343 return_address_register: Register(0),
5344 version: 4,
5345 address_size: mem::size_of::<usize>() as u8,
5346 initial_instructions: EndianSlice::new(&[], LittleEndian),
5347 augmentation: None,
5348 data_alignment_factor: 2,
5349 code_alignment_factor: 3,
5350 }
5351 }
5352
5353 #[test]
5354 fn test_eval_set_loc() {
5355 let cie = make_test_cie();
5356 let ctx = UnwindContext::new();
5357 let mut expected = ctx.clone();
5358 expected.row_mut().end_address = 42;
5359 let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })];
5360 assert_eval(ctx, expected, cie, None, instructions);
5361 }
5362
5363 #[test]
5364 fn test_eval_set_loc_backwards() {
5365 let cie = make_test_cie();
5366 let mut ctx = UnwindContext::new();
5367 ctx.row_mut().start_address = 999;
5368 let expected = ctx.clone();
5369 let instructions = [(
5370 Err(Error::InvalidAddressRange),
5371 CallFrameInstruction::SetLoc { address: 42 },
5372 )];
5373 assert_eval(ctx, expected, cie, None, instructions);
5374 }
5375
5376 #[test]
5377 fn test_eval_advance_loc() {
5378 let cie = make_test_cie();
5379 let mut ctx = UnwindContext::new();
5380 ctx.row_mut().start_address = 3;
5381 let mut expected = ctx.clone();
5382 expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor;
5383 let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })];
5384 assert_eval(ctx, expected, cie, None, instructions);
5385 }
5386
5387 #[test]
5388 fn test_eval_advance_loc_overflow_32() {
5389 let mut cie = make_test_cie();
5390 cie.address_size = 4;
5391 let mut ctx = UnwindContext::new();
5392 ctx.row_mut().start_address = u32::MAX.into();
5393 let expected = ctx.clone();
5394 let instructions = [(
5395 Err(Error::AddressOverflow),
5396 CallFrameInstruction::AdvanceLoc { delta: 42 },
5397 )];
5398 assert_eval(ctx, expected, cie, None, instructions);
5399 }
5400
5401 #[test]
5402 fn test_eval_advance_loc_overflow_64() {
5403 let mut cie = make_test_cie();
5404 cie.address_size = 8;
5405 let mut ctx = UnwindContext::new();
5406 ctx.row_mut().start_address = u64::MAX;
5407 let expected = ctx.clone();
5408 let instructions = [(
5409 Err(Error::AddressOverflow),
5410 CallFrameInstruction::AdvanceLoc { delta: 42 },
5411 )];
5412 assert_eval(ctx, expected, cie, None, instructions);
5413 }
5414
5415 #[test]
5416 fn test_eval_def_cfa() {
5417 let cie = make_test_cie();
5418 let ctx = UnwindContext::new();
5419 let mut expected = ctx.clone();
5420 expected.set_cfa(CfaRule::RegisterAndOffset {
5421 register: Register(42),
5422 offset: 36,
5423 });
5424 let instructions = [(
5425 Ok(false),
5426 CallFrameInstruction::DefCfa {
5427 register: Register(42),
5428 offset: 36,
5429 },
5430 )];
5431 assert_eval(ctx, expected, cie, None, instructions);
5432 }
5433
5434 #[test]
5435 fn test_eval_def_cfa_sf() {
5436 let cie = make_test_cie();
5437 let ctx = UnwindContext::new();
5438 let mut expected = ctx.clone();
5439 expected.set_cfa(CfaRule::RegisterAndOffset {
5440 register: Register(42),
5441 offset: 36 * cie.data_alignment_factor as i64,
5442 });
5443 let instructions = [(
5444 Ok(false),
5445 CallFrameInstruction::DefCfaSf {
5446 register: Register(42),
5447 factored_offset: 36,
5448 },
5449 )];
5450 assert_eval(ctx, expected, cie, None, instructions);
5451 }
5452
5453 #[test]
5454 fn test_eval_def_cfa_register() {
5455 let cie = make_test_cie();
5456 let mut ctx = UnwindContext::new();
5457 ctx.set_cfa(CfaRule::RegisterAndOffset {
5458 register: Register(3),
5459 offset: 8,
5460 });
5461 let mut expected = ctx.clone();
5462 expected.set_cfa(CfaRule::RegisterAndOffset {
5463 register: Register(42),
5464 offset: 8,
5465 });
5466 let instructions = [(
5467 Ok(false),
5468 CallFrameInstruction::DefCfaRegister {
5469 register: Register(42),
5470 },
5471 )];
5472 assert_eval(ctx, expected, cie, None, instructions);
5473 }
5474
5475 #[test]
5476 fn test_eval_def_cfa_register_invalid_context() {
5477 let cie = make_test_cie();
5478 let mut ctx = UnwindContext::new();
5479 ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5480 offset: 0,
5481 length: 0,
5482 }));
5483 let expected = ctx.clone();
5484 let instructions = [(
5485 Err(Error::CfiInstructionInInvalidContext),
5486 CallFrameInstruction::DefCfaRegister {
5487 register: Register(42),
5488 },
5489 )];
5490 assert_eval(ctx, expected, cie, None, instructions);
5491 }
5492
5493 #[test]
5494 fn test_eval_def_cfa_offset() {
5495 let cie = make_test_cie();
5496 let mut ctx = UnwindContext::new();
5497 ctx.set_cfa(CfaRule::RegisterAndOffset {
5498 register: Register(3),
5499 offset: 8,
5500 });
5501 let mut expected = ctx.clone();
5502 expected.set_cfa(CfaRule::RegisterAndOffset {
5503 register: Register(3),
5504 offset: 42,
5505 });
5506 let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })];
5507 assert_eval(ctx, expected, cie, None, instructions);
5508 }
5509
5510 #[test]
5511 fn test_eval_def_cfa_offset_invalid_context() {
5512 let cie = make_test_cie();
5513 let mut ctx = UnwindContext::new();
5514 ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5515 offset: 10,
5516 length: 11,
5517 }));
5518 let expected = ctx.clone();
5519 let instructions = [(
5520 Err(Error::CfiInstructionInInvalidContext),
5521 CallFrameInstruction::DefCfaOffset { offset: 1993 },
5522 )];
5523 assert_eval(ctx, expected, cie, None, instructions);
5524 }
5525
5526 #[test]
5527 fn test_eval_def_cfa_expression() {
5528 let expr = UnwindExpression {
5529 offset: 10,
5530 length: 11,
5531 };
5532 let cie = make_test_cie();
5533 let ctx = UnwindContext::new();
5534 let mut expected = ctx.clone();
5535 expected.set_cfa(CfaRule::Expression(expr));
5536 let instructions = [(
5537 Ok(false),
5538 CallFrameInstruction::DefCfaExpression { expression: expr },
5539 )];
5540 assert_eval(ctx, expected, cie, None, instructions);
5541 }
5542
5543 #[test]
5544 fn test_eval_undefined() {
5545 let cie = make_test_cie();
5546 let ctx = UnwindContext::new();
5547 let mut expected = ctx.clone();
5548 expected
5549 .set_register_rule(Register(5), RegisterRule::Undefined)
5550 .unwrap();
5551 let instructions = [(
5552 Ok(false),
5553 CallFrameInstruction::Undefined {
5554 register: Register(5),
5555 },
5556 )];
5557 assert_eval(ctx, expected, cie, None, instructions);
5558 }
5559
5560 #[test]
5561 fn test_eval_same_value() {
5562 let cie = make_test_cie();
5563 let ctx = UnwindContext::new();
5564 let mut expected = ctx.clone();
5565 expected
5566 .set_register_rule(Register(0), RegisterRule::SameValue)
5567 .unwrap();
5568 let instructions = [(
5569 Ok(false),
5570 CallFrameInstruction::SameValue {
5571 register: Register(0),
5572 },
5573 )];
5574 assert_eval(ctx, expected, cie, None, instructions);
5575 }
5576
5577 #[test]
5578 fn test_eval_offset() {
5579 let cie = make_test_cie();
5580 let ctx = UnwindContext::new();
5581 let mut expected = ctx.clone();
5582 expected
5583 .set_register_rule(
5584 Register(2),
5585 RegisterRule::Offset(3 * cie.data_alignment_factor),
5586 )
5587 .unwrap();
5588 let instructions = [(
5589 Ok(false),
5590 CallFrameInstruction::Offset {
5591 register: Register(2),
5592 factored_offset: 3,
5593 },
5594 )];
5595 assert_eval(ctx, expected, cie, None, instructions);
5596 }
5597
5598 #[test]
5599 fn test_eval_offset_extended_sf() {
5600 let cie = make_test_cie();
5601 let ctx = UnwindContext::new();
5602 let mut expected = ctx.clone();
5603 expected
5604 .set_register_rule(
5605 Register(4),
5606 RegisterRule::Offset(-3 * cie.data_alignment_factor),
5607 )
5608 .unwrap();
5609 let instructions = [(
5610 Ok(false),
5611 CallFrameInstruction::OffsetExtendedSf {
5612 register: Register(4),
5613 factored_offset: -3,
5614 },
5615 )];
5616 assert_eval(ctx, expected, cie, None, instructions);
5617 }
5618
5619 #[test]
5620 fn test_eval_val_offset() {
5621 let cie = make_test_cie();
5622 let ctx = UnwindContext::new();
5623 let mut expected = ctx.clone();
5624 expected
5625 .set_register_rule(
5626 Register(5),
5627 RegisterRule::ValOffset(7 * cie.data_alignment_factor),
5628 )
5629 .unwrap();
5630 let instructions = [(
5631 Ok(false),
5632 CallFrameInstruction::ValOffset {
5633 register: Register(5),
5634 factored_offset: 7,
5635 },
5636 )];
5637 assert_eval(ctx, expected, cie, None, instructions);
5638 }
5639
5640 #[test]
5641 fn test_eval_val_offset_sf() {
5642 let cie = make_test_cie();
5643 let ctx = UnwindContext::new();
5644 let mut expected = ctx.clone();
5645 expected
5646 .set_register_rule(
5647 Register(5),
5648 RegisterRule::ValOffset(-7 * cie.data_alignment_factor),
5649 )
5650 .unwrap();
5651 let instructions = [(
5652 Ok(false),
5653 CallFrameInstruction::ValOffsetSf {
5654 register: Register(5),
5655 factored_offset: -7,
5656 },
5657 )];
5658 assert_eval(ctx, expected, cie, None, instructions);
5659 }
5660
5661 #[test]
5662 fn test_eval_expression() {
5663 let expr = UnwindExpression {
5664 offset: 10,
5665 length: 11,
5666 };
5667 let cie = make_test_cie();
5668 let ctx = UnwindContext::new();
5669 let mut expected = ctx.clone();
5670 expected
5671 .set_register_rule(Register(9), RegisterRule::Expression(expr))
5672 .unwrap();
5673 let instructions = [(
5674 Ok(false),
5675 CallFrameInstruction::Expression {
5676 register: Register(9),
5677 expression: expr,
5678 },
5679 )];
5680 assert_eval(ctx, expected, cie, None, instructions);
5681 }
5682
5683 #[test]
5684 fn test_eval_val_expression() {
5685 let expr = UnwindExpression {
5686 offset: 10,
5687 length: 11,
5688 };
5689 let cie = make_test_cie();
5690 let ctx = UnwindContext::new();
5691 let mut expected = ctx.clone();
5692 expected
5693 .set_register_rule(Register(9), RegisterRule::ValExpression(expr))
5694 .unwrap();
5695 let instructions = [(
5696 Ok(false),
5697 CallFrameInstruction::ValExpression {
5698 register: Register(9),
5699 expression: expr,
5700 },
5701 )];
5702 assert_eval(ctx, expected, cie, None, instructions);
5703 }
5704
5705 #[test]
5706 fn test_eval_restore() {
5707 let cie = make_test_cie();
5708 let fde = FrameDescriptionEntry {
5709 offset: 0,
5710 format: Format::Dwarf64,
5711 length: 0,
5712 address_range: 0,
5713 augmentation: None,
5714 initial_address: 0,
5715 cie: cie.clone(),
5716 instructions: EndianSlice::new(&[], LittleEndian),
5717 };
5718
5719 let mut ctx = UnwindContext::new();
5720 ctx.set_register_rule(Register(0), RegisterRule::Offset(1))
5721 .unwrap();
5722 ctx.save_initial_rules().unwrap();
5723 let expected = ctx.clone();
5724 ctx.set_register_rule(Register(0), RegisterRule::Offset(2))
5725 .unwrap();
5726
5727 let instructions = [(
5728 Ok(false),
5729 CallFrameInstruction::Restore {
5730 register: Register(0),
5731 },
5732 )];
5733 assert_eval(ctx, expected, cie, Some(fde), instructions);
5734 }
5735
5736 #[test]
5737 fn test_eval_restore_havent_saved_initial_context() {
5738 let cie = make_test_cie();
5739 let ctx = UnwindContext::new();
5740 let expected = ctx.clone();
5741 let instructions = [(
5742 Err(Error::CfiInstructionInInvalidContext),
5743 CallFrameInstruction::Restore {
5744 register: Register(0),
5745 },
5746 )];
5747 assert_eval(ctx, expected, cie, None, instructions);
5748 }
5749
5750 #[test]
5751 fn test_eval_remember_state() {
5752 let cie = make_test_cie();
5753 let ctx = UnwindContext::new();
5754 let mut expected = ctx.clone();
5755 expected.push_row().unwrap();
5756 let instructions = [(Ok(false), CallFrameInstruction::RememberState)];
5757 assert_eval(ctx, expected, cie, None, instructions);
5758 }
5759
5760 #[test]
5761 fn test_eval_restore_state() {
5762 let cie = make_test_cie();
5763
5764 let mut ctx = UnwindContext::new();
5765 ctx.set_start_address(1);
5766 ctx.set_register_rule(Register(0), RegisterRule::SameValue)
5767 .unwrap();
5768 let mut expected = ctx.clone();
5769 ctx.push_row().unwrap();
5770 ctx.set_start_address(2);
5771 ctx.set_register_rule(Register(0), RegisterRule::Offset(16))
5772 .unwrap();
5773
5774 expected.set_start_address(2);
5776
5777 let instructions = [
5778 (Ok(false), CallFrameInstruction::RestoreState),
5780 (
5782 Err(Error::PopWithEmptyStack),
5783 CallFrameInstruction::RestoreState,
5784 ),
5785 ];
5786
5787 assert_eval(ctx, expected, cie, None, instructions);
5788 }
5789
5790 #[test]
5791 fn test_eval_negate_ra_state() {
5792 let cie = make_test_cie();
5793 let ctx = UnwindContext::new();
5794 let mut expected = ctx.clone();
5795 expected
5796 .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1))
5797 .unwrap();
5798 let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)];
5799 assert_eval(ctx, expected, cie, None, instructions);
5800
5801 let cie = make_test_cie();
5802 let ctx = UnwindContext::new();
5803 let mut expected = ctx.clone();
5804 expected
5805 .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0))
5806 .unwrap();
5807 let instructions = [
5808 (Ok(false), CallFrameInstruction::NegateRaState),
5809 (Ok(false), CallFrameInstruction::NegateRaState),
5810 ];
5811 assert_eval(ctx, expected, cie, None, instructions);
5812
5813 let cie = make_test_cie();
5815 let ctx = UnwindContext::new();
5816 let mut expected = ctx.clone();
5817 expected
5818 .set_register_rule(
5819 crate::AArch64::RA_SIGN_STATE,
5820 RegisterRule::Offset(cie.data_alignment_factor as i64),
5821 )
5822 .unwrap();
5823 let instructions = [
5824 (
5825 Ok(false),
5826 CallFrameInstruction::Offset {
5827 register: crate::AArch64::RA_SIGN_STATE,
5828 factored_offset: 1,
5829 },
5830 ),
5831 (
5832 Err(Error::CfiInstructionInInvalidContext),
5833 CallFrameInstruction::NegateRaState,
5834 ),
5835 ];
5836 assert_eval(ctx, expected, cie, None, instructions);
5837 }
5838
5839 #[test]
5840 fn test_eval_nop() {
5841 let cie = make_test_cie();
5842 let ctx = UnwindContext::new();
5843 let expected = ctx.clone();
5844 let instructions = [(Ok(false), CallFrameInstruction::Nop)];
5845 assert_eval(ctx, expected, cie, None, instructions);
5846 }
5847
5848 #[test]
5849 fn test_unwind_table_cie_no_rule() {
5850 let initial_instructions = Section::with_endian(Endian::Little)
5851 .D8(constants::DW_CFA_def_cfa_sf.0)
5853 .uleb(4)
5854 .sleb(-12)
5855 .append_repeated(constants::DW_CFA_nop.0, 4);
5856 let initial_instructions = initial_instructions.get_contents().unwrap();
5857
5858 let cie = CommonInformationEntry {
5859 offset: 0,
5860 length: 0,
5861 format: Format::Dwarf32,
5862 version: 4,
5863 augmentation: None,
5864 address_size: 8,
5865 code_alignment_factor: 1,
5866 data_alignment_factor: 1,
5867 return_address_register: Register(3),
5868 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5869 };
5870
5871 let instructions = Section::with_endian(Endian::Little)
5872 .append_repeated(constants::DW_CFA_nop.0, 8);
5874 let instructions = instructions.get_contents().unwrap();
5875
5876 let fde = FrameDescriptionEntry {
5877 offset: 0,
5878 length: 0,
5879 format: Format::Dwarf32,
5880 cie: cie.clone(),
5881 initial_address: 0,
5882 address_range: 100,
5883 augmentation: None,
5884 instructions: EndianSlice::new(&instructions, LittleEndian),
5885 };
5886
5887 let section = &DebugFrame::from(EndianSlice::default());
5888 let bases = &BaseAddresses::default();
5889 let mut ctx = Box::new(UnwindContext::new());
5890
5891 let mut table = fde
5892 .rows(section, bases, &mut ctx)
5893 .expect("Should run initial program OK");
5894 assert!(table.ctx.is_initialized);
5895 let expected_initial_rule = (Register(0), RegisterRule::Undefined);
5896 assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5897
5898 {
5899 let row = table.next_row().expect("Should evaluate first row OK");
5900 let expected = UnwindTableRow {
5901 start_address: 0,
5902 end_address: 100,
5903 saved_args_size: 0,
5904 cfa: CfaRule::RegisterAndOffset {
5905 register: Register(4),
5906 offset: -12,
5907 },
5908 registers: [].iter().collect(),
5909 };
5910 assert_eq!(Some(&expected), row);
5911 }
5912
5913 assert_eq!(Ok(None), table.next_row());
5915 assert_eq!(Ok(None), table.next_row());
5916 }
5917
5918 #[test]
5919 fn test_unwind_table_cie_single_rule() {
5920 let initial_instructions = Section::with_endian(Endian::Little)
5921 .D8(constants::DW_CFA_def_cfa_sf.0)
5923 .uleb(4)
5924 .sleb(-12)
5925 .D8(constants::DW_CFA_offset.0 | 3)
5927 .uleb(4)
5928 .append_repeated(constants::DW_CFA_nop.0, 4);
5929 let initial_instructions = initial_instructions.get_contents().unwrap();
5930
5931 let cie = CommonInformationEntry {
5932 offset: 0,
5933 length: 0,
5934 format: Format::Dwarf32,
5935 version: 4,
5936 augmentation: None,
5937 address_size: 8,
5938 code_alignment_factor: 1,
5939 data_alignment_factor: 1,
5940 return_address_register: Register(3),
5941 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5942 };
5943
5944 let instructions = Section::with_endian(Endian::Little)
5945 .append_repeated(constants::DW_CFA_nop.0, 8);
5947 let instructions = instructions.get_contents().unwrap();
5948
5949 let fde = FrameDescriptionEntry {
5950 offset: 0,
5951 length: 0,
5952 format: Format::Dwarf32,
5953 cie: cie.clone(),
5954 initial_address: 0,
5955 address_range: 100,
5956 augmentation: None,
5957 instructions: EndianSlice::new(&instructions, LittleEndian),
5958 };
5959
5960 let section = &DebugFrame::from(EndianSlice::default());
5961 let bases = &BaseAddresses::default();
5962 let mut ctx = Box::new(UnwindContext::new());
5963
5964 let mut table = fde
5965 .rows(section, bases, &mut ctx)
5966 .expect("Should run initial program OK");
5967 assert!(table.ctx.is_initialized);
5968 let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
5969 assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5970
5971 {
5972 let row = table.next_row().expect("Should evaluate first row OK");
5973 let expected = UnwindTableRow {
5974 start_address: 0,
5975 end_address: 100,
5976 saved_args_size: 0,
5977 cfa: CfaRule::RegisterAndOffset {
5978 register: Register(4),
5979 offset: -12,
5980 },
5981 registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(),
5982 };
5983 assert_eq!(Some(&expected), row);
5984 }
5985
5986 assert_eq!(Ok(None), table.next_row());
5988 assert_eq!(Ok(None), table.next_row());
5989 }
5990
5991 #[test]
5992 fn test_unwind_table_cie_invalid_rule() {
5993 let initial_instructions1 = Section::with_endian(Endian::Little)
5994 .D8(constants::DW_CFA_remember_state.0)
5996 .D8(constants::DW_CFA_offset.0 | 4)
5998 .uleb(8)
5999 .D8(constants::DW_CFA_offset.0);
6001 let initial_instructions1 = initial_instructions1.get_contents().unwrap();
6002
6003 let cie1 = CommonInformationEntry {
6004 offset: 0,
6005 length: 0,
6006 format: Format::Dwarf32,
6007 version: 4,
6008 augmentation: None,
6009 address_size: 8,
6010 code_alignment_factor: 1,
6011 data_alignment_factor: 1,
6012 return_address_register: Register(3),
6013 initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian),
6014 };
6015
6016 let initial_instructions2 = Section::with_endian(Endian::Little)
6017 .D8(constants::DW_CFA_offset.0 | 3)
6019 .uleb(4)
6020 .append_repeated(constants::DW_CFA_nop.0, 4);
6021 let initial_instructions2 = initial_instructions2.get_contents().unwrap();
6022
6023 let cie2 = CommonInformationEntry {
6024 offset: 0,
6025 length: 0,
6026 format: Format::Dwarf32,
6027 version: 4,
6028 augmentation: None,
6029 address_size: 8,
6030 code_alignment_factor: 1,
6031 data_alignment_factor: 1,
6032 return_address_register: Register(3),
6033 initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian),
6034 };
6035
6036 let fde1 = FrameDescriptionEntry {
6037 offset: 0,
6038 length: 0,
6039 format: Format::Dwarf32,
6040 cie: cie1.clone(),
6041 initial_address: 0,
6042 address_range: 100,
6043 augmentation: None,
6044 instructions: EndianSlice::new(&[], LittleEndian),
6045 };
6046
6047 let fde2 = FrameDescriptionEntry {
6048 offset: 0,
6049 length: 0,
6050 format: Format::Dwarf32,
6051 cie: cie2.clone(),
6052 initial_address: 0,
6053 address_range: 100,
6054 augmentation: None,
6055 instructions: EndianSlice::new(&[], LittleEndian),
6056 };
6057
6058 let section = &DebugFrame::from(EndianSlice::default());
6059 let bases = &BaseAddresses::default();
6060 let mut ctx = Box::new(UnwindContext::new());
6061
6062 let table = fde1
6063 .rows(section, bases, &mut ctx)
6064 .map_eof(&initial_instructions1);
6065 assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4))));
6066 assert!(!ctx.is_initialized);
6067 assert_eq!(ctx.stack.len(), 2);
6068 assert_eq!(ctx.initial_rule, None);
6069
6070 let _table = fde2
6071 .rows(section, bases, &mut ctx)
6072 .expect("Should run initial program OK");
6073 assert!(ctx.is_initialized);
6074 assert_eq!(ctx.stack.len(), 1);
6075 let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
6076 assert_eq!(ctx.initial_rule, Some(expected_initial_rule));
6077 }
6078
6079 #[test]
6080 fn test_unwind_table_next_row() {
6081 #[allow(clippy::identity_op)]
6082 let initial_instructions = Section::with_endian(Endian::Little)
6083 .D8(constants::DW_CFA_def_cfa_sf.0)
6085 .uleb(4)
6086 .sleb(-12)
6087 .D8(constants::DW_CFA_offset.0 | 0)
6089 .uleb(8)
6090 .D8(constants::DW_CFA_offset.0 | 3)
6092 .uleb(4)
6093 .append_repeated(constants::DW_CFA_nop.0, 4);
6094 let initial_instructions = initial_instructions.get_contents().unwrap();
6095
6096 let cie = CommonInformationEntry {
6097 offset: 0,
6098 length: 0,
6099 format: Format::Dwarf32,
6100 version: 4,
6101 augmentation: None,
6102 address_size: 8,
6103 code_alignment_factor: 1,
6104 data_alignment_factor: 1,
6105 return_address_register: Register(3),
6106 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
6107 };
6108
6109 let instructions = Section::with_endian(Endian::Little)
6110 .D8(constants::DW_CFA_advance_loc1.0)
6112 .D8(1)
6113 .D8(constants::DW_CFA_offset_extended_sf.0)
6115 .uleb(0)
6116 .sleb(-16)
6117 .D8(constants::DW_CFA_advance_loc1.0)
6119 .D8(32)
6120 .D8(constants::DW_CFA_offset_extended_sf.0)
6122 .uleb(3)
6123 .sleb(-4)
6124 .D8(constants::DW_CFA_advance_loc1.0)
6126 .D8(64)
6127 .D8(constants::DW_CFA_offset.0 | 5)
6129 .uleb(4)
6130 .append_repeated(constants::DW_CFA_nop.0, 8);
6132 let instructions = instructions.get_contents().unwrap();
6133
6134 let fde = FrameDescriptionEntry {
6135 offset: 0,
6136 length: 0,
6137 format: Format::Dwarf32,
6138 cie: cie.clone(),
6139 initial_address: 0,
6140 address_range: 100,
6141 augmentation: None,
6142 instructions: EndianSlice::new(&instructions, LittleEndian),
6143 };
6144
6145 let section = &DebugFrame::from(EndianSlice::default());
6146 let bases = &BaseAddresses::default();
6147 let mut ctx = Box::new(UnwindContext::new());
6148
6149 let mut table = fde
6150 .rows(section, bases, &mut ctx)
6151 .expect("Should run initial program OK");
6152 assert!(table.ctx.is_initialized);
6153 assert!(table.ctx.initial_rule.is_none());
6154 let expected_initial_rules: RegisterRuleMap<_> = [
6155 (Register(0), RegisterRule::Offset(8)),
6156 (Register(3), RegisterRule::Offset(4)),
6157 ]
6158 .iter()
6159 .collect();
6160 assert_eq!(table.ctx.stack[0].registers, expected_initial_rules);
6161
6162 {
6163 let row = table.next_row().expect("Should evaluate first row OK");
6164 let expected = UnwindTableRow {
6165 start_address: 0,
6166 end_address: 1,
6167 saved_args_size: 0,
6168 cfa: CfaRule::RegisterAndOffset {
6169 register: Register(4),
6170 offset: -12,
6171 },
6172 registers: [
6173 (Register(0), RegisterRule::Offset(8)),
6174 (Register(3), RegisterRule::Offset(4)),
6175 ]
6176 .iter()
6177 .collect(),
6178 };
6179 assert_eq!(Some(&expected), row);
6180 }
6181
6182 {
6183 let row = table.next_row().expect("Should evaluate second row OK");
6184 let expected = UnwindTableRow {
6185 start_address: 1,
6186 end_address: 33,
6187 saved_args_size: 0,
6188 cfa: CfaRule::RegisterAndOffset {
6189 register: Register(4),
6190 offset: -12,
6191 },
6192 registers: [
6193 (Register(0), RegisterRule::Offset(-16)),
6194 (Register(3), RegisterRule::Offset(4)),
6195 ]
6196 .iter()
6197 .collect(),
6198 };
6199 assert_eq!(Some(&expected), row);
6200 }
6201
6202 {
6203 let row = table.next_row().expect("Should evaluate third row OK");
6204 let expected = UnwindTableRow {
6205 start_address: 33,
6206 end_address: 97,
6207 saved_args_size: 0,
6208 cfa: CfaRule::RegisterAndOffset {
6209 register: Register(4),
6210 offset: -12,
6211 },
6212 registers: [
6213 (Register(0), RegisterRule::Offset(-16)),
6214 (Register(3), RegisterRule::Offset(-4)),
6215 ]
6216 .iter()
6217 .collect(),
6218 };
6219 assert_eq!(Some(&expected), row);
6220 }
6221
6222 {
6223 let row = table.next_row().expect("Should evaluate fourth row OK");
6224 let expected = UnwindTableRow {
6225 start_address: 97,
6226 end_address: 100,
6227 saved_args_size: 0,
6228 cfa: CfaRule::RegisterAndOffset {
6229 register: Register(4),
6230 offset: -12,
6231 },
6232 registers: [
6233 (Register(0), RegisterRule::Offset(-16)),
6234 (Register(3), RegisterRule::Offset(-4)),
6235 (Register(5), RegisterRule::Offset(4)),
6236 ]
6237 .iter()
6238 .collect(),
6239 };
6240 assert_eq!(Some(&expected), row);
6241 }
6242
6243 assert_eq!(Ok(None), table.next_row());
6245 assert_eq!(Ok(None), table.next_row());
6246 }
6247
6248 #[test]
6249 fn test_unwind_info_for_address_ok() {
6250 let instrs1 = Section::with_endian(Endian::Big)
6251 .D8(constants::DW_CFA_def_cfa_sf.0)
6253 .uleb(4)
6254 .sleb(-12);
6255 let instrs1 = instrs1.get_contents().unwrap();
6256
6257 let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
6258
6259 let instrs3 = Section::with_endian(Endian::Big)
6260 .D8(constants::DW_CFA_advance_loc1.0)
6262 .D8(100)
6263 .D8(constants::DW_CFA_offset_extended_sf.0)
6265 .uleb(0)
6266 .sleb(-16);
6267 let instrs3 = instrs3.get_contents().unwrap();
6268
6269 let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
6270
6271 let mut cie1 = CommonInformationEntry {
6272 offset: 0,
6273 length: 0,
6274 format: Format::Dwarf32,
6275 version: 4,
6276 augmentation: None,
6277 address_size: 8,
6278 code_alignment_factor: 1,
6279 data_alignment_factor: 1,
6280 return_address_register: Register(3),
6281 initial_instructions: EndianSlice::new(&instrs1, BigEndian),
6282 };
6283
6284 let mut cie2 = CommonInformationEntry {
6285 offset: 0,
6286 length: 0,
6287 format: Format::Dwarf32,
6288 version: 4,
6289 augmentation: None,
6290 address_size: 4,
6291 code_alignment_factor: 1,
6292 data_alignment_factor: 1,
6293 return_address_register: Register(1),
6294 initial_instructions: EndianSlice::new(&instrs2, BigEndian),
6295 };
6296
6297 let cie1_location = Label::new();
6298 let cie2_location = Label::new();
6299
6300 let kind = debug_frame_be();
6304 let section = Section::with_endian(kind.endian())
6305 .mark(&cie1_location)
6306 .cie(kind, None, &mut cie1)
6307 .mark(&cie2_location)
6308 .cie(kind, None, &mut cie2);
6309
6310 let mut fde1 = FrameDescriptionEntry {
6311 offset: 0,
6312 length: 0,
6313 format: Format::Dwarf32,
6314 cie: cie1.clone(),
6315 initial_address: 0xfeed_beef,
6316 address_range: 200,
6317 augmentation: None,
6318 instructions: EndianSlice::new(&instrs3, BigEndian),
6319 };
6320
6321 let mut fde2 = FrameDescriptionEntry {
6322 offset: 0,
6323 length: 0,
6324 format: Format::Dwarf32,
6325 cie: cie2.clone(),
6326 initial_address: 0xfeed_face,
6327 address_range: 9000,
6328 augmentation: None,
6329 instructions: EndianSlice::new(&instrs4, BigEndian),
6330 };
6331
6332 let section =
6333 section
6334 .fde(kind, &cie1_location, &mut fde1)
6335 .fde(kind, &cie2_location, &mut fde2);
6336 section.start().set_const(0);
6337
6338 let contents = section.get_contents().unwrap();
6339 let debug_frame = kind.section(&contents);
6340
6341 let bases = Default::default();
6343 let mut ctx = Box::new(UnwindContext::new());
6344 let result = debug_frame.unwind_info_for_address(
6345 &bases,
6346 &mut ctx,
6347 0xfeed_beef + 150,
6348 DebugFrame::cie_from_offset,
6349 );
6350 assert!(result.is_ok());
6351 let unwind_info = result.unwrap();
6352
6353 assert_eq!(
6354 *unwind_info,
6355 UnwindTableRow {
6356 start_address: fde1.initial_address() + 100,
6357 end_address: fde1.end_address(),
6358 saved_args_size: 0,
6359 cfa: CfaRule::RegisterAndOffset {
6360 register: Register(4),
6361 offset: -12,
6362 },
6363 registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(),
6364 }
6365 );
6366 }
6367
6368 #[test]
6369 fn test_unwind_info_for_address_not_found() {
6370 let debug_frame = DebugFrame::new(&[], NativeEndian);
6371 let bases = Default::default();
6372 let mut ctx = Box::new(UnwindContext::new());
6373 let result = debug_frame.unwind_info_for_address(
6374 &bases,
6375 &mut ctx,
6376 0xbadb_ad99,
6377 DebugFrame::cie_from_offset,
6378 );
6379 assert!(result.is_err());
6380 assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
6381 }
6382
6383 #[test]
6384 fn test_eh_frame_hdr_unknown_version() {
6385 let bases = BaseAddresses::default();
6386 let buf = &[42];
6387 let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8);
6388 assert!(result.is_err());
6389 assert_eq!(result.unwrap_err(), Error::UnknownVersion(42));
6390 }
6391
6392 #[test]
6393 fn test_eh_frame_hdr_omit_ehptr() {
6394 let section = Section::with_endian(Endian::Little)
6395 .L8(1)
6396 .L8(0xff)
6397 .L8(0x03)
6398 .L8(0x0b)
6399 .L32(2)
6400 .L32(10)
6401 .L32(1)
6402 .L32(20)
6403 .L32(2)
6404 .L32(0);
6405 let section = section.get_contents().unwrap();
6406 let bases = BaseAddresses::default();
6407 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6408 assert!(result.is_err());
6409 assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding);
6410 }
6411
6412 #[test]
6413 fn test_eh_frame_hdr_omit_count() {
6414 let section = Section::with_endian(Endian::Little)
6415 .L8(1)
6416 .L8(0x0b)
6417 .L8(0xff)
6418 .L8(0x0b)
6419 .L32(0x12345);
6420 let section = section.get_contents().unwrap();
6421 let bases = BaseAddresses::default();
6422 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6423 assert!(result.is_ok());
6424 let result = result.unwrap();
6425 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6426 assert!(result.table().is_none());
6427 }
6428
6429 #[test]
6430 fn test_eh_frame_hdr_omit_table() {
6431 let section = Section::with_endian(Endian::Little)
6432 .L8(1)
6433 .L8(0x0b)
6434 .L8(0x03)
6435 .L8(0xff)
6436 .L32(0x12345)
6437 .L32(2);
6438 let section = section.get_contents().unwrap();
6439 let bases = BaseAddresses::default();
6440 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6441 assert!(result.is_ok());
6442 let result = result.unwrap();
6443 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6444 assert!(result.table().is_none());
6445 }
6446
6447 #[test]
6448 fn test_eh_frame_hdr_varlen_table() {
6449 let section = Section::with_endian(Endian::Little)
6450 .L8(1)
6451 .L8(0x0b)
6452 .L8(0x03)
6453 .L8(0x01)
6454 .L32(0x12345)
6455 .L32(2);
6456 let section = section.get_contents().unwrap();
6457 let bases = BaseAddresses::default();
6458 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6459 assert!(result.is_ok());
6460 let result = result.unwrap();
6461 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6462 let table = result.table();
6463 assert!(table.is_some());
6464 let table = table.unwrap();
6465 assert_eq!(
6466 table.lookup(0, &bases),
6467 Err(Error::VariableLengthSearchTable)
6468 );
6469 }
6470
6471 #[test]
6472 fn test_eh_frame_hdr_indirect_length() {
6473 let section = Section::with_endian(Endian::Little)
6474 .L8(1)
6475 .L8(0x0b)
6476 .L8(0x83)
6477 .L8(0x0b)
6478 .L32(0x12345)
6479 .L32(2);
6480 let section = section.get_contents().unwrap();
6481 let bases = BaseAddresses::default();
6482 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6483 assert!(result.is_err());
6484 assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding);
6485 }
6486
6487 #[test]
6488 fn test_eh_frame_hdr_indirect_ptrs() {
6489 let section = Section::with_endian(Endian::Little)
6490 .L8(1)
6491 .L8(0x8b)
6492 .L8(0x03)
6493 .L8(0x8b)
6494 .L32(0x12345)
6495 .L32(2)
6496 .L32(10)
6497 .L32(1)
6498 .L32(20)
6499 .L32(2);
6500 let section = section.get_contents().unwrap();
6501 let bases = BaseAddresses::default();
6502 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6503 assert!(result.is_ok());
6504 let result = result.unwrap();
6505 assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345));
6506 let table = result.table();
6507 assert!(table.is_some());
6508 let table = table.unwrap();
6509 assert_eq!(
6510 table.lookup(0, &bases),
6511 Err(Error::UnsupportedPointerEncoding)
6512 );
6513 }
6514
6515 #[test]
6516 fn test_eh_frame_hdr_good() {
6517 let section = Section::with_endian(Endian::Little)
6518 .L8(1)
6519 .L8(0x0b)
6520 .L8(0x03)
6521 .L8(0x0b)
6522 .L32(0x12345)
6523 .L32(2)
6524 .L32(10)
6525 .L32(1)
6526 .L32(20)
6527 .L32(2);
6528 let section = section.get_contents().unwrap();
6529 let bases = BaseAddresses::default();
6530 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6531 assert!(result.is_ok());
6532 let result = result.unwrap();
6533 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6534 let table = result.table();
6535 assert!(table.is_some());
6536 let table = table.unwrap();
6537 assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1)));
6538 assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1)));
6539 assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1)));
6540 assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1)));
6541 assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1)));
6542 assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2)));
6543 assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2)));
6544 assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2)));
6545 }
6546
6547 #[test]
6548 fn test_eh_frame_fde_for_address_good() {
6549 let mut cie = make_test_cie();
6553 cie.format = Format::Dwarf32;
6554 cie.version = 1;
6555
6556 let start_of_cie = Label::new();
6557 let end_of_cie = Label::new();
6558
6559 let kind = eh_frame_le();
6560 let section = Section::with_endian(kind.endian())
6561 .append_repeated(0, 16)
6562 .mark(&start_of_cie)
6563 .cie(kind, None, &mut cie)
6564 .mark(&end_of_cie);
6565
6566 let mut fde1 = FrameDescriptionEntry {
6567 offset: 0,
6568 length: 0,
6569 format: Format::Dwarf32,
6570 cie: cie.clone(),
6571 initial_address: 9,
6572 address_range: 4,
6573 augmentation: None,
6574 instructions: EndianSlice::new(&[], LittleEndian),
6575 };
6576 let mut fde2 = FrameDescriptionEntry {
6577 offset: 0,
6578 length: 0,
6579 format: Format::Dwarf32,
6580 cie: cie.clone(),
6581 initial_address: 20,
6582 address_range: 8,
6583 augmentation: None,
6584 instructions: EndianSlice::new(&[], LittleEndian),
6585 };
6586
6587 let start_of_fde1 = Label::new();
6588 let start_of_fde2 = Label::new();
6589
6590 let section = section
6591 .mark(&start_of_fde1)
6593 .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1)
6594 .mark(&start_of_fde2)
6595 .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2);
6596
6597 section.start().set_const(0);
6598 let section = section.get_contents().unwrap();
6599 let eh_frame = kind.section(§ion);
6600
6601 let section = Section::with_endian(kind.endian())
6603 .L8(1)
6604 .L8(0x0b)
6605 .L8(0x03)
6606 .L8(0x0b)
6607 .L32(0x12345)
6608 .L32(2)
6609 .L32(10)
6610 .L32(0x12345 + start_of_fde1.value().unwrap() as u32)
6611 .L32(20)
6612 .L32(0x12345 + start_of_fde2.value().unwrap() as u32);
6613
6614 let section = section.get_contents().unwrap();
6615 let bases = BaseAddresses::default();
6616 let eh_frame_hdr = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6617 assert!(eh_frame_hdr.is_ok());
6618 let eh_frame_hdr = eh_frame_hdr.unwrap();
6619
6620 let table = eh_frame_hdr.table();
6621 assert!(table.is_some());
6622 let table = table.unwrap();
6623
6624 let bases = Default::default();
6625 let mut iter = table.iter(&bases);
6626 assert_eq!(
6627 iter.next(),
6628 Ok(Some((
6629 Pointer::Direct(10),
6630 Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6631 )))
6632 );
6633 assert_eq!(
6634 iter.next(),
6635 Ok(Some((
6636 Pointer::Direct(20),
6637 Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6638 )))
6639 );
6640 assert_eq!(iter.next(), Ok(None));
6641
6642 assert_eq!(
6643 table.iter(&bases).nth(0),
6644 Ok(Some((
6645 Pointer::Direct(10),
6646 Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6647 )))
6648 );
6649
6650 assert_eq!(
6651 table.iter(&bases).nth(1),
6652 Ok(Some((
6653 Pointer::Direct(20),
6654 Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6655 )))
6656 );
6657 assert_eq!(table.iter(&bases).nth(2), Ok(None));
6658
6659 let f = |_: &_, _: &_, o: EhFrameOffset| {
6660 assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6661 Ok(cie.clone())
6662 };
6663 assert_eq!(
6664 table.fde_for_address(&eh_frame, &bases, 9, f),
6665 Ok(fde1.clone())
6666 );
6667 assert_eq!(
6668 table.fde_for_address(&eh_frame, &bases, 10, f),
6669 Ok(fde1.clone())
6670 );
6671 assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1));
6672 assert_eq!(
6673 table.fde_for_address(&eh_frame, &bases, 19, f),
6674 Err(Error::NoUnwindInfoForAddress)
6675 );
6676 assert_eq!(
6677 table.fde_for_address(&eh_frame, &bases, 20, f),
6678 Ok(fde2.clone())
6679 );
6680 assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2));
6681 assert_eq!(
6682 table.fde_for_address(&eh_frame, &bases, 100_000, f),
6683 Err(Error::NoUnwindInfoForAddress)
6684 );
6685 }
6686
6687 #[test]
6688 fn test_eh_frame_stops_at_zero_length() {
6689 let section = Section::with_endian(Endian::Little).L32(0);
6690 let section = section.get_contents().unwrap();
6691 let rest = &mut EndianSlice::new(§ion, LittleEndian);
6692 let bases = Default::default();
6693
6694 assert_eq!(
6695 parse_cfi_entry(&bases, &EhFrame::new(§ion, LittleEndian), rest),
6696 Ok(None)
6697 );
6698
6699 assert_eq!(
6700 EhFrame::new(§ion, LittleEndian).cie_from_offset(&bases, EhFrameOffset(0)),
6701 Err(Error::NoEntryAtGivenOffset)
6702 );
6703 }
6704
6705 fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result<usize> {
6706 let mut fde = FrameDescriptionEntry {
6707 offset: 0,
6708 length: 0,
6709 format: Format::Dwarf64,
6710 cie: make_test_cie(),
6711 initial_address: 0xfeed_beef,
6712 address_range: 39,
6713 augmentation: None,
6714 instructions: EndianSlice::new(&[], LittleEndian),
6715 };
6716
6717 let kind = eh_frame_le();
6718 let section = Section::with_endian(kind.endian())
6719 .append_bytes(buf)
6720 .fde(kind, cie_offset as u64, &mut fde)
6721 .append_bytes(buf);
6722
6723 let section = section.get_contents().unwrap();
6724 let eh_frame = kind.section(§ion);
6725 let input = &mut EndianSlice::new(§ion[buf.len()..], LittleEndian);
6726
6727 let bases = Default::default();
6728 match parse_cfi_entry(&bases, &eh_frame, input) {
6729 Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0),
6730 Err(e) => Err(e),
6731 otherwise => panic!("Unexpected result: {:#?}", otherwise),
6732 }
6733 }
6734
6735 #[test]
6736 fn test_eh_frame_resolve_cie_offset_ok() {
6737 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6738 let cie_offset = 2;
6739 assert_eq!(
6741 resolve_cie_offset(&buf, buf.len() + 4 - cie_offset),
6742 Ok(cie_offset)
6743 );
6744 }
6745
6746 #[test]
6747 fn test_eh_frame_resolve_cie_offset_out_of_bounds() {
6748 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6749 assert_eq!(
6750 resolve_cie_offset(&buf, buf.len() + 4 + 2),
6751 Err(Error::OffsetOutOfBounds)
6752 );
6753 }
6754
6755 #[test]
6756 fn test_eh_frame_resolve_cie_offset_underflow() {
6757 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6758 assert_eq!(
6759 resolve_cie_offset(&buf, usize::MAX),
6760 Err(Error::OffsetOutOfBounds)
6761 );
6762 }
6763
6764 #[test]
6765 fn test_eh_frame_fde_ok() {
6766 let mut cie = make_test_cie();
6767 cie.format = Format::Dwarf32;
6768 cie.version = 1;
6769
6770 let start_of_cie = Label::new();
6771 let end_of_cie = Label::new();
6772
6773 let kind = eh_frame_le();
6776 let section = Section::with_endian(kind.endian())
6777 .append_repeated(0, 16)
6778 .mark(&start_of_cie)
6779 .cie(kind, None, &mut cie)
6780 .mark(&end_of_cie);
6781
6782 let mut fde = FrameDescriptionEntry {
6783 offset: 0,
6784 length: 0,
6785 format: Format::Dwarf32,
6786 cie: cie.clone(),
6787 initial_address: 0xfeed_beef,
6788 address_range: 999,
6789 augmentation: None,
6790 instructions: EndianSlice::new(&[], LittleEndian),
6791 };
6792
6793 let section = section
6794 .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde);
6796
6797 section.start().set_const(0);
6798 let section = section.get_contents().unwrap();
6799 let eh_frame = kind.section(§ion);
6800 let section = EndianSlice::new(§ion, LittleEndian);
6801
6802 let mut offset = None;
6803 let result = parse_fde(
6804 eh_frame,
6805 &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6806 |_, _, o| {
6807 offset = Some(o);
6808 assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6809 Ok(cie.clone())
6810 },
6811 );
6812 match result {
6813 Ok(actual) => assert_eq!(actual, fde),
6814 otherwise => panic!("Unexpected result {:?}", otherwise),
6815 }
6816 assert!(offset.is_some());
6817 }
6818
6819 #[test]
6820 fn test_eh_frame_fde_out_of_bounds() {
6821 let mut cie = make_test_cie();
6822 cie.version = 1;
6823
6824 let end_of_cie = Label::new();
6825
6826 let mut fde = FrameDescriptionEntry {
6827 offset: 0,
6828 length: 0,
6829 format: Format::Dwarf64,
6830 cie: cie.clone(),
6831 initial_address: 0xfeed_beef,
6832 address_range: 999,
6833 augmentation: None,
6834 instructions: EndianSlice::new(&[], LittleEndian),
6835 };
6836
6837 let kind = eh_frame_le();
6838 let section = Section::with_endian(kind.endian())
6839 .cie(kind, None, &mut cie)
6840 .mark(&end_of_cie)
6841 .fde(kind, 99_999_999_999_999, &mut fde);
6842
6843 section.start().set_const(0);
6844 let section = section.get_contents().unwrap();
6845 let eh_frame = kind.section(§ion);
6846 let section = EndianSlice::new(§ion, LittleEndian);
6847
6848 let result = parse_fde(
6849 eh_frame,
6850 &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6851 UnwindSection::cie_from_offset,
6852 );
6853 assert_eq!(result, Err(Error::OffsetOutOfBounds));
6854 }
6855
6856 #[test]
6857 fn test_augmentation_parse_not_z_augmentation() {
6858 let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian);
6859 let bases = Default::default();
6860 let address_size = 8;
6861 let section = EhFrame::new(&[], NativeEndian);
6862 let input = &mut EndianSlice::new(&[], NativeEndian);
6863 assert_eq!(
6864 Augmentation::parse(augmentation, &bases, address_size, §ion, input),
6865 Err(Error::UnknownAugmentation)
6866 );
6867 }
6868
6869 #[test]
6870 fn test_augmentation_parse_just_signal_trampoline() {
6871 let aug_str = &mut EndianSlice::new(b"S", LittleEndian);
6872 let bases = Default::default();
6873 let address_size = 8;
6874 let section = EhFrame::new(&[], LittleEndian);
6875 let input = &mut EndianSlice::new(&[], LittleEndian);
6876
6877 let augmentation = Augmentation {
6878 is_signal_trampoline: true,
6879 ..Default::default()
6880 };
6881
6882 assert_eq!(
6883 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6884 Ok(augmentation)
6885 );
6886 }
6887
6888 #[test]
6889 fn test_augmentation_parse_unknown_part_of_z_augmentation() {
6890 let bases = Default::default();
6892 let address_size = 8;
6893 let section = Section::with_endian(Endian::Little)
6894 .uleb(4)
6895 .append_repeated(4, 4)
6896 .get_contents()
6897 .unwrap();
6898 let section = EhFrame::new(§ion, LittleEndian);
6899 let input = &mut section.section().clone();
6900 let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian);
6901 assert_eq!(
6902 Augmentation::parse(augmentation, &bases, address_size, §ion, input),
6903 Err(Error::UnknownAugmentation)
6904 );
6905 }
6906
6907 #[test]
6908 #[allow(non_snake_case)]
6909 fn test_augmentation_parse_L() {
6910 let bases = Default::default();
6911 let address_size = 8;
6912 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6913
6914 let section = Section::with_endian(Endian::Little)
6915 .uleb(1)
6916 .D8(constants::DW_EH_PE_uleb128.0)
6917 .append_bytes(&rest)
6918 .get_contents()
6919 .unwrap();
6920 let section = EhFrame::new(§ion, LittleEndian);
6921 let input = &mut section.section().clone();
6922 let aug_str = &mut EndianSlice::new(b"zL", LittleEndian);
6923
6924 let augmentation = Augmentation {
6925 lsda: Some(constants::DW_EH_PE_uleb128),
6926 ..Default::default()
6927 };
6928
6929 assert_eq!(
6930 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6931 Ok(augmentation)
6932 );
6933 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6934 }
6935
6936 #[test]
6937 #[allow(non_snake_case)]
6938 fn test_augmentation_parse_P() {
6939 let bases = Default::default();
6940 let address_size = 8;
6941 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6942
6943 let section = Section::with_endian(Endian::Little)
6944 .uleb(9)
6945 .D8(constants::DW_EH_PE_udata8.0)
6946 .L64(0xf00d_f00d)
6947 .append_bytes(&rest)
6948 .get_contents()
6949 .unwrap();
6950 let section = EhFrame::new(§ion, LittleEndian);
6951 let input = &mut section.section().clone();
6952 let aug_str = &mut EndianSlice::new(b"zP", LittleEndian);
6953
6954 let augmentation = Augmentation {
6955 personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))),
6956 ..Default::default()
6957 };
6958
6959 assert_eq!(
6960 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6961 Ok(augmentation)
6962 );
6963 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6964 }
6965
6966 #[test]
6967 #[allow(non_snake_case)]
6968 fn test_augmentation_parse_R() {
6969 let bases = Default::default();
6970 let address_size = 8;
6971 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6972
6973 let section = Section::with_endian(Endian::Little)
6974 .uleb(1)
6975 .D8(constants::DW_EH_PE_udata4.0)
6976 .append_bytes(&rest)
6977 .get_contents()
6978 .unwrap();
6979 let section = EhFrame::new(§ion, LittleEndian);
6980 let input = &mut section.section().clone();
6981 let aug_str = &mut EndianSlice::new(b"zR", LittleEndian);
6982
6983 let augmentation = Augmentation {
6984 fde_address_encoding: Some(constants::DW_EH_PE_udata4),
6985 ..Default::default()
6986 };
6987
6988 assert_eq!(
6989 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6990 Ok(augmentation)
6991 );
6992 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6993 }
6994
6995 #[test]
6996 #[allow(non_snake_case)]
6997 fn test_augmentation_parse_S() {
6998 let bases = Default::default();
6999 let address_size = 8;
7000 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7001
7002 let section = Section::with_endian(Endian::Little)
7003 .uleb(0)
7004 .append_bytes(&rest)
7005 .get_contents()
7006 .unwrap();
7007 let section = EhFrame::new(§ion, LittleEndian);
7008 let input = &mut section.section().clone();
7009 let aug_str = &mut EndianSlice::new(b"zS", LittleEndian);
7010
7011 let augmentation = Augmentation {
7012 is_signal_trampoline: true,
7013 ..Default::default()
7014 };
7015
7016 assert_eq!(
7017 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
7018 Ok(augmentation)
7019 );
7020 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7021 }
7022
7023 #[test]
7024 fn test_augmentation_parse_all() {
7025 let bases = Default::default();
7026 let address_size = 8;
7027 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7028
7029 let section = Section::with_endian(Endian::Little)
7030 .uleb(1 + 9 + 1)
7031 .D8(constants::DW_EH_PE_uleb128.0)
7033 .D8(constants::DW_EH_PE_udata8.0)
7035 .L64(0x1bad_f00d)
7036 .D8(constants::DW_EH_PE_uleb128.0)
7038 .append_bytes(&rest)
7039 .get_contents()
7040 .unwrap();
7041 let section = EhFrame::new(§ion, LittleEndian);
7042 let input = &mut section.section().clone();
7043 let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian);
7044
7045 let augmentation = Augmentation {
7046 lsda: Some(constants::DW_EH_PE_uleb128),
7047 personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))),
7048 fde_address_encoding: Some(constants::DW_EH_PE_uleb128),
7049 is_signal_trampoline: true,
7050 };
7051
7052 assert_eq!(
7053 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
7054 Ok(augmentation)
7055 );
7056 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7057 }
7058
7059 #[test]
7060 fn test_eh_frame_fde_no_augmentation() {
7061 let instrs = [1, 2, 3, 4];
7062 let cie_offset = 1;
7063
7064 let mut cie = make_test_cie();
7065 cie.format = Format::Dwarf32;
7066 cie.version = 1;
7067
7068 let mut fde = FrameDescriptionEntry {
7069 offset: 0,
7070 length: 0,
7071 format: Format::Dwarf32,
7072 cie: cie.clone(),
7073 initial_address: 0xfeed_face,
7074 address_range: 9000,
7075 augmentation: None,
7076 instructions: EndianSlice::new(&instrs, LittleEndian),
7077 };
7078
7079 let rest = [1, 2, 3, 4];
7080
7081 let kind = eh_frame_le();
7082 let section = Section::with_endian(kind.endian())
7083 .fde(kind, cie_offset, &mut fde)
7084 .append_bytes(&rest)
7085 .get_contents()
7086 .unwrap();
7087 let section = kind.section(§ion);
7088 let input = &mut section.section().clone();
7089
7090 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7091 assert_eq!(result, Ok(fde));
7092 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7093 }
7094
7095 #[test]
7096 fn test_eh_frame_fde_empty_augmentation() {
7097 let instrs = [1, 2, 3, 4];
7098 let cie_offset = 1;
7099
7100 let mut cie = make_test_cie();
7101 cie.format = Format::Dwarf32;
7102 cie.version = 1;
7103 cie.augmentation = Some(Augmentation::default());
7104
7105 let mut fde = FrameDescriptionEntry {
7106 offset: 0,
7107 length: 0,
7108 format: Format::Dwarf32,
7109 cie: cie.clone(),
7110 initial_address: 0xfeed_face,
7111 address_range: 9000,
7112 augmentation: Some(AugmentationData::default()),
7113 instructions: EndianSlice::new(&instrs, LittleEndian),
7114 };
7115
7116 let rest = [1, 2, 3, 4];
7117
7118 let kind = eh_frame_le();
7119 let section = Section::with_endian(kind.endian())
7120 .fde(kind, cie_offset, &mut fde)
7121 .append_bytes(&rest)
7122 .get_contents()
7123 .unwrap();
7124 let section = kind.section(§ion);
7125 let input = &mut section.section().clone();
7126
7127 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7128 assert_eq!(result, Ok(fde));
7129 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7130 }
7131
7132 #[test]
7133 fn test_eh_frame_fde_lsda_augmentation() {
7134 let instrs = [1, 2, 3, 4];
7135 let cie_offset = 1;
7136
7137 let mut cie = make_test_cie();
7138 cie.format = Format::Dwarf32;
7139 cie.version = 1;
7140 cie.augmentation = Some(Augmentation::default());
7141 cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr);
7142
7143 let mut fde = FrameDescriptionEntry {
7144 offset: 0,
7145 length: 0,
7146 format: Format::Dwarf32,
7147 cie: cie.clone(),
7148 initial_address: 0xfeed_face,
7149 address_range: 9000,
7150 augmentation: Some(AugmentationData {
7151 lsda: Some(Pointer::Direct(0x1122_3344)),
7152 }),
7153 instructions: EndianSlice::new(&instrs, LittleEndian),
7154 };
7155
7156 let rest = [1, 2, 3, 4];
7157
7158 let kind = eh_frame_le();
7159 let section = Section::with_endian(kind.endian())
7160 .fde(kind, cie_offset, &mut fde)
7161 .append_bytes(&rest)
7162 .get_contents()
7163 .unwrap();
7164 let section = kind.section(§ion);
7165 let input = &mut section.section().clone();
7166
7167 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7168 assert_eq!(result, Ok(fde));
7169 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7170 }
7171
7172 #[test]
7173 fn test_eh_frame_fde_lsda_function_relative() {
7174 let instrs = [1, 2, 3, 4];
7175 let cie_offset = 1;
7176
7177 let mut cie = make_test_cie();
7178 cie.format = Format::Dwarf32;
7179 cie.version = 1;
7180 cie.augmentation = Some(Augmentation::default());
7181 cie.augmentation.as_mut().unwrap().lsda =
7182 Some(constants::DW_EH_PE_funcrel | constants::DW_EH_PE_absptr);
7183
7184 let mut fde = FrameDescriptionEntry {
7185 offset: 0,
7186 length: 0,
7187 format: Format::Dwarf32,
7188 cie: cie.clone(),
7189 initial_address: 0xfeed_face,
7190 address_range: 9000,
7191 augmentation: Some(AugmentationData {
7192 lsda: Some(Pointer::Direct(0xbeef)),
7193 }),
7194 instructions: EndianSlice::new(&instrs, LittleEndian),
7195 };
7196
7197 let rest = [1, 2, 3, 4];
7198
7199 let kind = eh_frame_le();
7200 let section = Section::with_endian(kind.endian())
7201 .append_repeated(10, 10)
7202 .fde(kind, cie_offset, &mut fde)
7203 .append_bytes(&rest)
7204 .get_contents()
7205 .unwrap();
7206 let section = kind.section(§ion);
7207 let input = &mut section.section().range_from(10..);
7208
7209 fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef));
7211
7212 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7213 assert_eq!(result, Ok(fde));
7214 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7215 }
7216
7217 #[test]
7218 fn test_eh_frame_cie_personality_function_relative_bad_context() {
7219 let instrs = [1, 2, 3, 4];
7220
7221 let length = Label::new();
7222 let start = Label::new();
7223 let end = Label::new();
7224
7225 let aug_len = Label::new();
7226 let aug_start = Label::new();
7227 let aug_end = Label::new();
7228
7229 let section = Section::with_endian(Endian::Little)
7230 .L32(&length)
7232 .mark(&start)
7233 .L32(0)
7235 .D8(1)
7237 .append_bytes(b"zP\0")
7239 .uleb(1)
7241 .sleb(1)
7243 .uleb(1)
7245 .D8(&aug_len)
7249 .mark(&aug_start)
7250 .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0)
7252 .uleb(1)
7253 .mark(&aug_end)
7254 .append_bytes(&instrs)
7256 .mark(&end);
7257
7258 length.set_const((&end - &start) as u64);
7259 aug_len.set_const((&aug_end - &aug_start) as u64);
7260
7261 let section = section.get_contents().unwrap();
7262 let section = EhFrame::new(§ion, LittleEndian);
7263
7264 let bases = BaseAddresses::default();
7265 let mut iter = section.entries(&bases);
7266 assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext));
7267 }
7268
7269 #[test]
7270 fn register_rule_map_eq() {
7271 let map1: RegisterRuleMap<usize> = [
7273 (Register(0), RegisterRule::SameValue),
7274 (Register(3), RegisterRule::Offset(1)),
7275 ]
7276 .iter()
7277 .collect();
7278 let map2: RegisterRuleMap<usize> = [
7279 (Register(3), RegisterRule::Offset(1)),
7280 (Register(0), RegisterRule::SameValue),
7281 ]
7282 .iter()
7283 .collect();
7284 assert_eq!(map1, map2);
7285 assert_eq!(map2, map1);
7286
7287 let map3: RegisterRuleMap<usize> = [
7289 (Register(0), RegisterRule::SameValue),
7290 (Register(2), RegisterRule::Offset(1)),
7291 ]
7292 .iter()
7293 .collect();
7294 let map4: RegisterRuleMap<usize> = [
7295 (Register(3), RegisterRule::Offset(1)),
7296 (Register(0), RegisterRule::SameValue),
7297 ]
7298 .iter()
7299 .collect();
7300 assert!(map3 != map4);
7301 assert!(map4 != map3);
7302
7303 let mut map5 = RegisterRuleMap::<usize>::default();
7305 map5.set(Register(0), RegisterRule::SameValue).unwrap();
7306 map5.set(Register(0), RegisterRule::Undefined).unwrap();
7307 let map6 = RegisterRuleMap::<usize>::default();
7308 assert_eq!(map5, map6);
7309 assert_eq!(map6, map5);
7310 }
7311
7312 #[test]
7313 fn iter_register_rules() {
7314 let row = UnwindTableRow::<usize> {
7315 registers: [
7316 (Register(0), RegisterRule::SameValue),
7317 (Register(1), RegisterRule::Offset(1)),
7318 (Register(2), RegisterRule::ValOffset(2)),
7319 ]
7320 .iter()
7321 .collect(),
7322 ..Default::default()
7323 };
7324
7325 let mut found0 = false;
7326 let mut found1 = false;
7327 let mut found2 = false;
7328
7329 for &(register, ref rule) in row.registers() {
7330 match register.0 {
7331 0 => {
7332 assert!(!found0);
7333 found0 = true;
7334 assert_eq!(*rule, RegisterRule::SameValue);
7335 }
7336 1 => {
7337 assert!(!found1);
7338 found1 = true;
7339 assert_eq!(*rule, RegisterRule::Offset(1));
7340 }
7341 2 => {
7342 assert!(!found2);
7343 found2 = true;
7344 assert_eq!(*rule, RegisterRule::ValOffset(2));
7345 }
7346 x => panic!("Unexpected register rule: ({}, {:?})", x, rule),
7347 }
7348 }
7349
7350 assert!(found0);
7351 assert!(found1);
7352 assert!(found2);
7353 }
7354
7355 #[test]
7356 #[cfg(target_pointer_width = "64")]
7357 fn size_of_unwind_ctx() {
7358 use core::mem;
7359 let size = mem::size_of::<UnwindContext<usize>>();
7360 let max_size = 30968;
7361 if size > max_size {
7362 assert_eq!(size, max_size);
7363 }
7364 }
7365
7366 #[test]
7367 #[cfg(target_pointer_width = "64")]
7368 fn size_of_register_rule_map() {
7369 use core::mem;
7370 let size = mem::size_of::<RegisterRuleMap<usize>>();
7371 let max_size = 6152;
7372 if size > max_size {
7373 assert_eq!(size, max_size);
7374 }
7375 }
7376
7377 #[test]
7378 fn test_parse_pointer_encoding_ok() {
7379 use crate::endianity::NativeEndian;
7380 let expected = constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_pcrel;
7381 let input = [expected.0, 1, 2, 3, 4];
7382 let input = &mut EndianSlice::new(&input, NativeEndian);
7383 assert_eq!(parse_pointer_encoding(input), Ok(expected));
7384 assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian));
7385 }
7386
7387 #[test]
7388 fn test_parse_pointer_encoding_bad_encoding() {
7389 use crate::endianity::NativeEndian;
7390 let expected =
7391 constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0);
7392 let input = [expected.0, 1, 2, 3, 4];
7393 let input = &mut EndianSlice::new(&input, NativeEndian);
7394 assert_eq!(
7395 Err(Error::UnknownPointerEncoding(expected)),
7396 parse_pointer_encoding(input)
7397 );
7398 }
7399
7400 #[test]
7401 fn test_parse_encoded_pointer_absptr() {
7402 let encoding = constants::DW_EH_PE_absptr;
7403 let expected_rest = [1, 2, 3, 4];
7404
7405 let input = Section::with_endian(Endian::Little)
7406 .L32(0xf00d_f00d)
7407 .append_bytes(&expected_rest);
7408 let input = input.get_contents().unwrap();
7409 let input = EndianSlice::new(&input, LittleEndian);
7410 let mut rest = input;
7411
7412 let parameters = PointerEncodingParameters {
7413 bases: &SectionBaseAddresses::default(),
7414 func_base: None,
7415 address_size: 4,
7416 section: &input,
7417 };
7418 assert_eq!(
7419 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7420 Ok(Pointer::Direct(0xf00d_f00d))
7421 );
7422 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7423 }
7424
7425 #[test]
7426 fn test_parse_encoded_pointer_pcrel() {
7427 let encoding = constants::DW_EH_PE_pcrel;
7428 let expected_rest = [1, 2, 3, 4];
7429
7430 let input = Section::with_endian(Endian::Little)
7431 .append_repeated(0, 0x10)
7432 .L32(0x1)
7433 .append_bytes(&expected_rest);
7434 let input = input.get_contents().unwrap();
7435 let input = EndianSlice::new(&input, LittleEndian);
7436 let mut rest = input.range_from(0x10..);
7437
7438 let parameters = PointerEncodingParameters {
7439 bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame,
7440 func_base: None,
7441 address_size: 4,
7442 section: &input,
7443 };
7444 assert_eq!(
7445 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7446 Ok(Pointer::Direct(0x111))
7447 );
7448 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7449 }
7450
7451 #[test]
7452 fn test_parse_encoded_pointer_pcrel_undefined() {
7453 let encoding = constants::DW_EH_PE_pcrel;
7454
7455 let input = Section::with_endian(Endian::Little).L32(0x1);
7456 let input = input.get_contents().unwrap();
7457 let input = EndianSlice::new(&input, LittleEndian);
7458 let mut rest = input;
7459
7460 let parameters = PointerEncodingParameters {
7461 bases: &SectionBaseAddresses::default(),
7462 func_base: None,
7463 address_size: 4,
7464 section: &input,
7465 };
7466 assert_eq!(
7467 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7468 Err(Error::PcRelativePointerButSectionBaseIsUndefined)
7469 );
7470 }
7471
7472 #[test]
7473 fn test_parse_encoded_pointer_textrel() {
7474 let encoding = constants::DW_EH_PE_textrel;
7475 let expected_rest = [1, 2, 3, 4];
7476
7477 let input = Section::with_endian(Endian::Little)
7478 .L32(0x1)
7479 .append_bytes(&expected_rest);
7480 let input = input.get_contents().unwrap();
7481 let input = EndianSlice::new(&input, LittleEndian);
7482 let mut rest = input;
7483
7484 let parameters = PointerEncodingParameters {
7485 bases: &BaseAddresses::default().set_text(0x10).eh_frame,
7486 func_base: None,
7487 address_size: 4,
7488 section: &input,
7489 };
7490 assert_eq!(
7491 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7492 Ok(Pointer::Direct(0x11))
7493 );
7494 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7495 }
7496
7497 #[test]
7498 fn test_parse_encoded_pointer_textrel_undefined() {
7499 let encoding = constants::DW_EH_PE_textrel;
7500
7501 let input = Section::with_endian(Endian::Little).L32(0x1);
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: &SectionBaseAddresses::default(),
7508 func_base: None,
7509 address_size: 4,
7510 section: &input,
7511 };
7512 assert_eq!(
7513 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7514 Err(Error::TextRelativePointerButTextBaseIsUndefined)
7515 );
7516 }
7517
7518 #[test]
7519 fn test_parse_encoded_pointer_datarel() {
7520 let encoding = constants::DW_EH_PE_datarel;
7521 let expected_rest = [1, 2, 3, 4];
7522
7523 let input = Section::with_endian(Endian::Little)
7524 .L32(0x1)
7525 .append_bytes(&expected_rest);
7526 let input = input.get_contents().unwrap();
7527 let input = EndianSlice::new(&input, LittleEndian);
7528 let mut rest = input;
7529
7530 let parameters = PointerEncodingParameters {
7531 bases: &BaseAddresses::default().set_got(0x10).eh_frame,
7532 func_base: None,
7533 address_size: 4,
7534 section: &input,
7535 };
7536 assert_eq!(
7537 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7538 Ok(Pointer::Direct(0x11))
7539 );
7540 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7541 }
7542
7543 #[test]
7544 fn test_parse_encoded_pointer_datarel_undefined() {
7545 let encoding = constants::DW_EH_PE_datarel;
7546
7547 let input = Section::with_endian(Endian::Little).L32(0x1);
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: &SectionBaseAddresses::default(),
7554 func_base: None,
7555 address_size: 4,
7556 section: &input,
7557 };
7558 assert_eq!(
7559 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7560 Err(Error::DataRelativePointerButDataBaseIsUndefined)
7561 );
7562 }
7563
7564 #[test]
7565 fn test_parse_encoded_pointer_funcrel() {
7566 let encoding = constants::DW_EH_PE_funcrel;
7567 let expected_rest = [1, 2, 3, 4];
7568
7569 let input = Section::with_endian(Endian::Little)
7570 .L32(0x1)
7571 .append_bytes(&expected_rest);
7572 let input = input.get_contents().unwrap();
7573 let input = EndianSlice::new(&input, LittleEndian);
7574 let mut rest = input;
7575
7576 let parameters = PointerEncodingParameters {
7577 bases: &SectionBaseAddresses::default(),
7578 func_base: Some(0x10),
7579 address_size: 4,
7580 section: &input,
7581 };
7582 assert_eq!(
7583 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7584 Ok(Pointer::Direct(0x11))
7585 );
7586 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7587 }
7588
7589 #[test]
7590 fn test_parse_encoded_pointer_funcrel_undefined() {
7591 let encoding = constants::DW_EH_PE_funcrel;
7592
7593 let input = Section::with_endian(Endian::Little).L32(0x1);
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: None,
7601 address_size: 4,
7602 section: &input,
7603 };
7604 assert_eq!(
7605 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7606 Err(Error::FuncRelativePointerInBadContext)
7607 );
7608 }
7609
7610 #[test]
7611 fn test_parse_encoded_pointer_uleb128() {
7612 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_uleb128;
7613 let expected_rest = [1, 2, 3, 4];
7614
7615 let input = Section::with_endian(Endian::Little)
7616 .uleb(0x12_3456)
7617 .append_bytes(&expected_rest);
7618 let input = input.get_contents().unwrap();
7619 let input = EndianSlice::new(&input, LittleEndian);
7620 let mut rest = input;
7621
7622 let parameters = PointerEncodingParameters {
7623 bases: &SectionBaseAddresses::default(),
7624 func_base: None,
7625 address_size: 4,
7626 section: &input,
7627 };
7628 assert_eq!(
7629 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7630 Ok(Pointer::Direct(0x12_3456))
7631 );
7632 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7633 }
7634
7635 #[test]
7636 fn test_parse_encoded_pointer_udata2() {
7637 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata2;
7638 let expected_rest = [1, 2, 3, 4];
7639
7640 let input = Section::with_endian(Endian::Little)
7641 .L16(0x1234)
7642 .append_bytes(&expected_rest);
7643 let input = input.get_contents().unwrap();
7644 let input = EndianSlice::new(&input, LittleEndian);
7645 let mut rest = input;
7646
7647 let parameters = PointerEncodingParameters {
7648 bases: &SectionBaseAddresses::default(),
7649 func_base: None,
7650 address_size: 4,
7651 section: &input,
7652 };
7653 assert_eq!(
7654 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7655 Ok(Pointer::Direct(0x1234))
7656 );
7657 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7658 }
7659
7660 #[test]
7661 fn test_parse_encoded_pointer_udata4() {
7662 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata4;
7663 let expected_rest = [1, 2, 3, 4];
7664
7665 let input = Section::with_endian(Endian::Little)
7666 .L32(0x1234_5678)
7667 .append_bytes(&expected_rest);
7668 let input = input.get_contents().unwrap();
7669 let input = EndianSlice::new(&input, LittleEndian);
7670 let mut rest = input;
7671
7672 let parameters = PointerEncodingParameters {
7673 bases: &SectionBaseAddresses::default(),
7674 func_base: None,
7675 address_size: 4,
7676 section: &input,
7677 };
7678 assert_eq!(
7679 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7680 Ok(Pointer::Direct(0x1234_5678))
7681 );
7682 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7683 }
7684
7685 #[test]
7686 fn test_parse_encoded_pointer_udata8() {
7687 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata8;
7688 let expected_rest = [1, 2, 3, 4];
7689
7690 let input = Section::with_endian(Endian::Little)
7691 .L64(0x1234_5678_1234_5678)
7692 .append_bytes(&expected_rest);
7693 let input = input.get_contents().unwrap();
7694 let input = EndianSlice::new(&input, LittleEndian);
7695 let mut rest = input;
7696
7697 let parameters = PointerEncodingParameters {
7698 bases: &SectionBaseAddresses::default(),
7699 func_base: None,
7700 address_size: 8,
7701 section: &input,
7702 };
7703 assert_eq!(
7704 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7705 Ok(Pointer::Direct(0x1234_5678_1234_5678))
7706 );
7707 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7708 }
7709
7710 #[test]
7711 fn test_parse_encoded_pointer_sleb128() {
7712 let encoding = constants::DW_EH_PE_textrel | constants::DW_EH_PE_sleb128;
7713 let expected_rest = [1, 2, 3, 4];
7714
7715 let input = Section::with_endian(Endian::Little)
7716 .sleb(-0x1111)
7717 .append_bytes(&expected_rest);
7718 let input = input.get_contents().unwrap();
7719 let input = EndianSlice::new(&input, LittleEndian);
7720 let mut rest = input;
7721
7722 let parameters = PointerEncodingParameters {
7723 bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame,
7724 func_base: None,
7725 address_size: 4,
7726 section: &input,
7727 };
7728 assert_eq!(
7729 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7730 Ok(Pointer::Direct(0x1111_0000))
7731 );
7732 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7733 }
7734
7735 #[test]
7736 fn test_parse_encoded_pointer_sdata2() {
7737 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata2;
7738 let expected_rest = [1, 2, 3, 4];
7739 let expected = 0x111_i16;
7740
7741 let input = Section::with_endian(Endian::Little)
7742 .L16(expected as u16)
7743 .append_bytes(&expected_rest);
7744 let input = input.get_contents().unwrap();
7745 let input = EndianSlice::new(&input, LittleEndian);
7746 let mut rest = input;
7747
7748 let parameters = PointerEncodingParameters {
7749 bases: &SectionBaseAddresses::default(),
7750 func_base: None,
7751 address_size: 4,
7752 section: &input,
7753 };
7754 assert_eq!(
7755 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7756 Ok(Pointer::Direct(expected as u64))
7757 );
7758 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7759 }
7760
7761 #[test]
7762 fn test_parse_encoded_pointer_sdata4() {
7763 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata4;
7764 let expected_rest = [1, 2, 3, 4];
7765 let expected = 0x111_1111_i32;
7766
7767 let input = Section::with_endian(Endian::Little)
7768 .L32(expected as u32)
7769 .append_bytes(&expected_rest);
7770 let input = input.get_contents().unwrap();
7771 let input = EndianSlice::new(&input, LittleEndian);
7772 let mut rest = input;
7773
7774 let parameters = PointerEncodingParameters {
7775 bases: &SectionBaseAddresses::default(),
7776 func_base: None,
7777 address_size: 4,
7778 section: &input,
7779 };
7780 assert_eq!(
7781 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7782 Ok(Pointer::Direct(expected as u64))
7783 );
7784 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7785 }
7786
7787 #[test]
7788 fn test_parse_encoded_pointer_sdata8() {
7789 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata8;
7790 let expected_rest = [1, 2, 3, 4];
7791 let expected = -0x11_1111_1222_2222_i64;
7792
7793 let input = Section::with_endian(Endian::Little)
7794 .L64(expected as u64)
7795 .append_bytes(&expected_rest);
7796 let input = input.get_contents().unwrap();
7797 let input = EndianSlice::new(&input, LittleEndian);
7798 let mut rest = input;
7799
7800 let parameters = PointerEncodingParameters {
7801 bases: &SectionBaseAddresses::default(),
7802 func_base: None,
7803 address_size: 8,
7804 section: &input,
7805 };
7806 assert_eq!(
7807 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7808 Ok(Pointer::Direct(expected as u64))
7809 );
7810 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7811 }
7812
7813 #[test]
7814 fn test_parse_encoded_pointer_omit() {
7815 let encoding = constants::DW_EH_PE_omit;
7816
7817 let input = Section::with_endian(Endian::Little).L32(0x1);
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: 4,
7826 section: &input,
7827 };
7828 assert_eq!(
7829 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7830 Err(Error::CannotParseOmitPointerEncoding)
7831 );
7832 assert_eq!(rest, input);
7833 }
7834
7835 #[test]
7836 fn test_parse_encoded_pointer_bad_encoding() {
7837 let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1);
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::UnknownPointerEncoding(encoding))
7853 );
7854 }
7855
7856 #[test]
7857 fn test_parse_encoded_pointer_aligned() {
7858 let encoding = constants::DW_EH_PE_aligned;
7861
7862 let input = Section::with_endian(Endian::Little).L32(0x1);
7863 let input = input.get_contents().unwrap();
7864 let input = EndianSlice::new(&input, LittleEndian);
7865 let mut rest = input;
7866
7867 let parameters = PointerEncodingParameters {
7868 bases: &SectionBaseAddresses::default(),
7869 func_base: None,
7870 address_size: 4,
7871 section: &input,
7872 };
7873 assert_eq!(
7874 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7875 Err(Error::UnsupportedPointerEncoding)
7876 );
7877 }
7878
7879 #[test]
7880 fn test_parse_encoded_pointer_indirect() {
7881 let expected_rest = [1, 2, 3, 4];
7882 let encoding = constants::DW_EH_PE_indirect;
7883
7884 let input = Section::with_endian(Endian::Little)
7885 .L32(0x1234_5678)
7886 .append_bytes(&expected_rest);
7887 let input = input.get_contents().unwrap();
7888 let input = EndianSlice::new(&input, LittleEndian);
7889 let mut rest = input;
7890
7891 let parameters = PointerEncodingParameters {
7892 bases: &SectionBaseAddresses::default(),
7893 func_base: None,
7894 address_size: 4,
7895 section: &input,
7896 };
7897 assert_eq!(
7898 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7899 Ok(Pointer::Indirect(0x1234_5678))
7900 );
7901 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7902 }
7903
7904 #[test]
7905 fn test_unwind_context_reuse() {
7906 fn unwind_one(ctx: &mut UnwindContext<usize>, data: &[u8]) {
7907 let debug_frame = DebugFrame::new(data, NativeEndian);
7908 let bases = Default::default();
7909 let result = debug_frame.unwind_info_for_address(
7910 &bases,
7911 ctx,
7912 0xbadb_ad99,
7913 DebugFrame::cie_from_offset,
7914 );
7915 assert!(result.is_err());
7916 assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
7917 }
7918
7919 let mut ctx: UnwindContext<usize> = UnwindContext::new();
7921 {
7922 let data1 = vec![];
7923 unwind_one(&mut ctx, &data1);
7924 }
7925 {
7926 let data2 = vec![];
7927 unwind_one(&mut ctx, &data2);
7928 }
7929 }
7930}