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