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