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.is_empty());
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.is_empty());
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.is_empty());
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)]
2961pub enum CallFrameInstruction<T: ReaderOffset> {
2962 SetLoc {
2973 address: u64,
2975 },
2976
2977 AdvanceLoc {
2989 delta: u32,
2991 },
2992
2993 DefCfa {
3001 register: Register,
3003 offset: u64,
3005 },
3006
3007 DefCfaSf {
3015 register: Register,
3017 factored_offset: i64,
3019 },
3020
3021 DefCfaRegister {
3029 register: Register,
3031 },
3032
3033 DefCfaOffset {
3041 offset: u64,
3043 },
3044
3045 DefCfaOffsetSf {
3054 factored_offset: i64,
3056 },
3057
3058 DefCfaExpression {
3065 expression: UnwindExpression<T>,
3067 },
3068
3069 Undefined {
3076 register: Register,
3078 },
3079
3080 SameValue {
3086 register: Register,
3088 },
3089
3090 Offset {
3101 register: Register,
3103 factored_offset: u64,
3105 },
3106
3107 OffsetExtendedSf {
3116 register: Register,
3118 factored_offset: i64,
3120 },
3121
3122 ValOffset {
3130 register: Register,
3132 factored_offset: u64,
3134 },
3135
3136 ValOffsetSf {
3144 register: Register,
3146 factored_offset: i64,
3148 },
3149
3150 Register {
3157 dest_register: Register,
3159 src_register: Register,
3162 },
3163
3164 Expression {
3174 register: Register,
3176 expression: UnwindExpression<T>,
3178 },
3179
3180 ValExpression {
3191 register: Register,
3193 expression: UnwindExpression<T>,
3195 },
3196
3197 Restore {
3207 register: Register,
3209 },
3210
3211 RememberState,
3218
3219 RestoreState,
3225
3226 ArgsSize {
3234 size: u64,
3236 },
3237
3238 NegateRaState,
3248
3249 Nop,
3255}
3256
3257const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000;
3258const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK;
3259
3260impl<T: ReaderOffset> CallFrameInstruction<T> {
3261 fn parse<R: Reader<Offset = T>>(
3262 input: &mut R,
3263 address_encoding: Option<DwEhPe>,
3264 parameters: &PointerEncodingParameters<'_, R>,
3265 vendor: Vendor,
3266 ) -> Result<CallFrameInstruction<T>> {
3267 let instruction = input.read_u8()?;
3268 let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK;
3269
3270 if high_bits == constants::DW_CFA_advance_loc.0 {
3271 let delta = instruction & CFI_INSTRUCTION_LOW_BITS_MASK;
3272 return Ok(CallFrameInstruction::AdvanceLoc {
3273 delta: u32::from(delta),
3274 });
3275 }
3276
3277 if high_bits == constants::DW_CFA_offset.0 {
3278 let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3279 let offset = input.read_uleb128()?;
3280 return Ok(CallFrameInstruction::Offset {
3281 register,
3282 factored_offset: offset,
3283 });
3284 }
3285
3286 if high_bits == constants::DW_CFA_restore.0 {
3287 let register = Register((instruction & CFI_INSTRUCTION_LOW_BITS_MASK).into());
3288 return Ok(CallFrameInstruction::Restore { register });
3289 }
3290
3291 debug_assert_eq!(high_bits, 0);
3292 let instruction = constants::DwCfa(instruction);
3293
3294 match instruction {
3295 constants::DW_CFA_nop => Ok(CallFrameInstruction::Nop),
3296
3297 constants::DW_CFA_set_loc => {
3298 let address = if let Some(encoding) = address_encoding {
3299 parse_encoded_pointer(encoding, parameters, input)?.direct()?
3300 } else {
3301 input.read_address(parameters.address_size)?
3302 };
3303 Ok(CallFrameInstruction::SetLoc { address })
3304 }
3305
3306 constants::DW_CFA_advance_loc1 => {
3307 let delta = input.read_u8()?;
3308 Ok(CallFrameInstruction::AdvanceLoc {
3309 delta: u32::from(delta),
3310 })
3311 }
3312
3313 constants::DW_CFA_advance_loc2 => {
3314 let delta = input.read_u16()?;
3315 Ok(CallFrameInstruction::AdvanceLoc {
3316 delta: u32::from(delta),
3317 })
3318 }
3319
3320 constants::DW_CFA_advance_loc4 => {
3321 let delta = input.read_u32()?;
3322 Ok(CallFrameInstruction::AdvanceLoc { delta })
3323 }
3324
3325 constants::DW_CFA_offset_extended => {
3326 let register = input.read_uleb128().and_then(Register::from_u64)?;
3327 let offset = input.read_uleb128()?;
3328 Ok(CallFrameInstruction::Offset {
3329 register,
3330 factored_offset: offset,
3331 })
3332 }
3333
3334 constants::DW_CFA_restore_extended => {
3335 let register = input.read_uleb128().and_then(Register::from_u64)?;
3336 Ok(CallFrameInstruction::Restore { register })
3337 }
3338
3339 constants::DW_CFA_undefined => {
3340 let register = input.read_uleb128().and_then(Register::from_u64)?;
3341 Ok(CallFrameInstruction::Undefined { register })
3342 }
3343
3344 constants::DW_CFA_same_value => {
3345 let register = input.read_uleb128().and_then(Register::from_u64)?;
3346 Ok(CallFrameInstruction::SameValue { register })
3347 }
3348
3349 constants::DW_CFA_register => {
3350 let dest = input.read_uleb128().and_then(Register::from_u64)?;
3351 let src = input.read_uleb128().and_then(Register::from_u64)?;
3352 Ok(CallFrameInstruction::Register {
3353 dest_register: dest,
3354 src_register: src,
3355 })
3356 }
3357
3358 constants::DW_CFA_remember_state => Ok(CallFrameInstruction::RememberState),
3359
3360 constants::DW_CFA_restore_state => Ok(CallFrameInstruction::RestoreState),
3361
3362 constants::DW_CFA_def_cfa => {
3363 let register = input.read_uleb128().and_then(Register::from_u64)?;
3364 let offset = input.read_uleb128()?;
3365 Ok(CallFrameInstruction::DefCfa { register, offset })
3366 }
3367
3368 constants::DW_CFA_def_cfa_register => {
3369 let register = input.read_uleb128().and_then(Register::from_u64)?;
3370 Ok(CallFrameInstruction::DefCfaRegister { register })
3371 }
3372
3373 constants::DW_CFA_def_cfa_offset => {
3374 let offset = input.read_uleb128()?;
3375 Ok(CallFrameInstruction::DefCfaOffset { offset })
3376 }
3377
3378 constants::DW_CFA_def_cfa_expression => {
3379 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3380 let offset = input.offset_from(parameters.section);
3381 input.skip(length)?;
3382 Ok(CallFrameInstruction::DefCfaExpression {
3383 expression: UnwindExpression { offset, length },
3384 })
3385 }
3386
3387 constants::DW_CFA_expression => {
3388 let register = input.read_uleb128().and_then(Register::from_u64)?;
3389 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3390 let offset = input.offset_from(parameters.section);
3391 input.skip(length)?;
3392 Ok(CallFrameInstruction::Expression {
3393 register,
3394 expression: UnwindExpression { offset, length },
3395 })
3396 }
3397
3398 constants::DW_CFA_offset_extended_sf => {
3399 let register = input.read_uleb128().and_then(Register::from_u64)?;
3400 let offset = input.read_sleb128()?;
3401 Ok(CallFrameInstruction::OffsetExtendedSf {
3402 register,
3403 factored_offset: offset,
3404 })
3405 }
3406
3407 constants::DW_CFA_def_cfa_sf => {
3408 let register = input.read_uleb128().and_then(Register::from_u64)?;
3409 let offset = input.read_sleb128()?;
3410 Ok(CallFrameInstruction::DefCfaSf {
3411 register,
3412 factored_offset: offset,
3413 })
3414 }
3415
3416 constants::DW_CFA_def_cfa_offset_sf => {
3417 let offset = input.read_sleb128()?;
3418 Ok(CallFrameInstruction::DefCfaOffsetSf {
3419 factored_offset: offset,
3420 })
3421 }
3422
3423 constants::DW_CFA_val_offset => {
3424 let register = input.read_uleb128().and_then(Register::from_u64)?;
3425 let offset = input.read_uleb128()?;
3426 Ok(CallFrameInstruction::ValOffset {
3427 register,
3428 factored_offset: offset,
3429 })
3430 }
3431
3432 constants::DW_CFA_val_offset_sf => {
3433 let register = input.read_uleb128().and_then(Register::from_u64)?;
3434 let offset = input.read_sleb128()?;
3435 Ok(CallFrameInstruction::ValOffsetSf {
3436 register,
3437 factored_offset: offset,
3438 })
3439 }
3440
3441 constants::DW_CFA_val_expression => {
3442 let register = input.read_uleb128().and_then(Register::from_u64)?;
3443 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
3444 let offset = input.offset_from(parameters.section);
3445 input.skip(length)?;
3446 Ok(CallFrameInstruction::ValExpression {
3447 register,
3448 expression: UnwindExpression { offset, length },
3449 })
3450 }
3451
3452 constants::DW_CFA_GNU_args_size => {
3453 let size = input.read_uleb128()?;
3454 Ok(CallFrameInstruction::ArgsSize { size })
3455 }
3456
3457 constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => {
3458 Ok(CallFrameInstruction::NegateRaState)
3459 }
3460
3461 otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
3462 }
3463 }
3464}
3465
3466#[derive(Clone, Debug)]
3471pub struct CallFrameInstructionIter<'a, R: Reader> {
3472 input: R,
3473 address_encoding: Option<constants::DwEhPe>,
3474 parameters: PointerEncodingParameters<'a, R>,
3475 vendor: Vendor,
3476}
3477
3478impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
3479 pub fn next(&mut self) -> Result<Option<CallFrameInstruction<R::Offset>>> {
3481 if self.input.is_empty() {
3482 return Ok(None);
3483 }
3484
3485 match CallFrameInstruction::parse(
3486 &mut self.input,
3487 self.address_encoding,
3488 &self.parameters,
3489 self.vendor,
3490 ) {
3491 Ok(instruction) => Ok(Some(instruction)),
3492 Err(e) => {
3493 self.input.empty();
3494 Err(e)
3495 }
3496 }
3497 }
3498}
3499
3500#[cfg(feature = "fallible-iterator")]
3501impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> {
3502 type Item = CallFrameInstruction<R::Offset>;
3503 type Error = Error;
3504
3505 fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
3506 CallFrameInstructionIter::next(self)
3507 }
3508}
3509
3510#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3537pub struct UnwindExpression<T: ReaderOffset> {
3538 pub offset: T,
3540 pub length: T,
3542}
3543
3544impl<T: ReaderOffset> UnwindExpression<T> {
3545 pub fn get<R, S>(&self, section: &S) -> Result<Expression<R>>
3550 where
3551 R: Reader<Offset = T>,
3552 S: UnwindSection<R>,
3553 {
3554 let input = &mut section.section().clone();
3555 input.skip(self.offset)?;
3556 let data = input.split(self.length)?;
3557 Ok(Expression(data))
3558 }
3559}
3560
3561#[doc(hidden)]
3563#[inline]
3564fn parse_pointer_encoding<R: Reader>(input: &mut R) -> Result<constants::DwEhPe> {
3565 let eh_pe = input.read_u8()?;
3566 let eh_pe = constants::DwEhPe(eh_pe);
3567
3568 if eh_pe.is_valid_encoding() {
3569 Ok(eh_pe)
3570 } else {
3571 Err(Error::UnknownPointerEncoding(eh_pe))
3572 }
3573}
3574
3575#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3577pub enum Pointer {
3578 Direct(u64),
3580
3581 Indirect(u64),
3588}
3589
3590impl Default for Pointer {
3591 #[inline]
3592 fn default() -> Self {
3593 Pointer::Direct(0)
3594 }
3595}
3596
3597impl Pointer {
3598 #[inline]
3599 fn new(encoding: constants::DwEhPe, address: u64) -> Pointer {
3600 if encoding.is_indirect() {
3601 Pointer::Indirect(address)
3602 } else {
3603 Pointer::Direct(address)
3604 }
3605 }
3606
3607 #[inline]
3609 pub fn direct(self) -> Result<u64> {
3610 match self {
3611 Pointer::Direct(p) => Ok(p),
3612 Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding),
3613 }
3614 }
3615
3616 #[inline]
3618 pub fn pointer(self) -> u64 {
3619 match self {
3620 Pointer::Direct(p) | Pointer::Indirect(p) => p,
3621 }
3622 }
3623}
3624
3625#[derive(Clone, Debug)]
3626struct PointerEncodingParameters<'a, R: Reader> {
3627 bases: &'a SectionBaseAddresses,
3628 func_base: Option<u64>,
3629 address_size: u8,
3630 section: &'a R,
3631}
3632
3633fn parse_encoded_pointer<R: Reader>(
3634 encoding: constants::DwEhPe,
3635 parameters: &PointerEncodingParameters<'_, R>,
3636 input: &mut R,
3637) -> Result<Pointer> {
3638 if !encoding.is_valid_encoding() {
3640 return Err(Error::UnknownPointerEncoding(encoding));
3641 }
3642
3643 if encoding == constants::DW_EH_PE_omit {
3644 return Err(Error::CannotParseOmitPointerEncoding);
3645 }
3646
3647 let base = match encoding.application() {
3648 constants::DW_EH_PE_absptr => 0,
3649 constants::DW_EH_PE_pcrel => {
3650 if let Some(section_base) = parameters.bases.section {
3651 let offset_from_section = input.offset_from(parameters.section);
3652 section_base
3653 .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size)
3654 } else {
3655 return Err(Error::PcRelativePointerButSectionBaseIsUndefined);
3656 }
3657 }
3658 constants::DW_EH_PE_textrel => {
3659 if let Some(text) = parameters.bases.text {
3660 text
3661 } else {
3662 return Err(Error::TextRelativePointerButTextBaseIsUndefined);
3663 }
3664 }
3665 constants::DW_EH_PE_datarel => {
3666 if let Some(data) = parameters.bases.data {
3667 data
3668 } else {
3669 return Err(Error::DataRelativePointerButDataBaseIsUndefined);
3670 }
3671 }
3672 constants::DW_EH_PE_funcrel => {
3673 if let Some(func) = parameters.func_base {
3674 func
3675 } else {
3676 return Err(Error::FuncRelativePointerInBadContext);
3677 }
3678 }
3679 constants::DW_EH_PE_aligned => return Err(Error::UnsupportedPointerEncoding),
3680 _ => unreachable!(),
3681 };
3682
3683 let offset = parse_encoded_value(encoding, parameters, input)?;
3684 Ok(Pointer::new(
3685 encoding,
3686 base.wrapping_add_sized(offset, parameters.address_size),
3687 ))
3688}
3689
3690fn parse_encoded_value<R: Reader>(
3691 encoding: constants::DwEhPe,
3692 parameters: &PointerEncodingParameters<'_, R>,
3693 input: &mut R,
3694) -> Result<u64> {
3695 match encoding.format() {
3696 constants::DW_EH_PE_absptr => input.read_address(parameters.address_size),
3698 constants::DW_EH_PE_uleb128 => input.read_uleb128(),
3699 constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from),
3700 constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from),
3701 constants::DW_EH_PE_udata8 => input.read_u64(),
3702
3703 constants::DW_EH_PE_sleb128 => input.read_sleb128().map(|a| a as u64),
3708 constants::DW_EH_PE_sdata2 => input.read_i16().map(|a| a as u64),
3709 constants::DW_EH_PE_sdata4 => input.read_i32().map(|a| a as u64),
3710 constants::DW_EH_PE_sdata8 => input.read_i64().map(|a| a as u64),
3711
3712 _ => unreachable!(),
3714 }
3715}
3716
3717#[cfg(test)]
3718mod tests {
3719 use super::*;
3720 use super::{parse_cfi_entry, AugmentationData, RegisterRuleMap, UnwindContext};
3721 use crate::common::Format;
3722 use crate::constants;
3723 use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian};
3724 use crate::read::{
3725 EndianSlice, Error, Pointer, ReaderOffsetId, Result, Section as ReadSection,
3726 };
3727 use crate::test_util::GimliSectionMethods;
3728 use alloc::boxed::Box;
3729 use alloc::vec::Vec;
3730 use core::marker::PhantomData;
3731 use core::mem;
3732 use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum};
3733
3734 #[derive(Clone, Copy)]
3736 struct SectionKind<Section>(PhantomData<Section>);
3737
3738 impl<T> SectionKind<T> {
3739 fn endian<'input, E>(self) -> Endian
3740 where
3741 E: Endianity,
3742 T: UnwindSection<EndianSlice<'input, E>>,
3743 T::Offset: UnwindOffset<usize>,
3744 {
3745 if E::default().is_big_endian() {
3746 Endian::Big
3747 } else {
3748 Endian::Little
3749 }
3750 }
3751
3752 fn section<'input, E>(self, contents: &'input [u8]) -> T
3753 where
3754 E: Endianity,
3755 T: UnwindSection<EndianSlice<'input, E>> + ReadSection<EndianSlice<'input, E>>,
3756 T::Offset: UnwindOffset<usize>,
3757 {
3758 EndianSlice::new(contents, E::default()).into()
3759 }
3760 }
3761
3762 fn debug_frame_le<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, LittleEndian>>> {
3763 SectionKind(PhantomData)
3764 }
3765
3766 fn debug_frame_be<'a>() -> SectionKind<DebugFrame<EndianSlice<'a, BigEndian>>> {
3767 SectionKind(PhantomData)
3768 }
3769
3770 fn eh_frame_le<'a>() -> SectionKind<EhFrame<EndianSlice<'a, LittleEndian>>> {
3771 SectionKind(PhantomData)
3772 }
3773
3774 fn parse_fde<Section, O, F, R>(
3775 section: Section,
3776 input: &mut R,
3777 get_cie: F,
3778 ) -> Result<FrameDescriptionEntry<R>>
3779 where
3780 R: Reader,
3781 Section: UnwindSection<R, Offset = O>,
3782 O: UnwindOffset<R::Offset>,
3783 F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>,
3784 {
3785 let bases = Default::default();
3786 match parse_cfi_entry(&bases, §ion, input) {
3787 Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie),
3788 Ok(_) => Err(Error::NoEntryAtGivenOffset),
3789 Err(e) => Err(e),
3790 }
3791 }
3792
3793 trait CfiSectionMethods: GimliSectionMethods {
3796 fn cie<'aug, 'input, E, T>(
3797 self,
3798 _kind: SectionKind<T>,
3799 augmentation: Option<&'aug str>,
3800 cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3801 ) -> Self
3802 where
3803 E: Endianity,
3804 T: UnwindSection<EndianSlice<'input, E>>,
3805 T::Offset: UnwindOffset;
3806 fn fde<'a, 'input, E, T, L>(
3807 self,
3808 _kind: SectionKind<T>,
3809 cie_offset: L,
3810 fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3811 ) -> Self
3812 where
3813 E: Endianity,
3814 T: UnwindSection<EndianSlice<'input, E>>,
3815 T::Offset: UnwindOffset,
3816 L: ToLabelOrNum<'a, u64>;
3817 }
3818
3819 impl CfiSectionMethods for Section {
3820 fn cie<'aug, 'input, E, T>(
3821 self,
3822 _kind: SectionKind<T>,
3823 augmentation: Option<&'aug str>,
3824 cie: &mut CommonInformationEntry<EndianSlice<'input, E>>,
3825 ) -> Self
3826 where
3827 E: Endianity,
3828 T: UnwindSection<EndianSlice<'input, E>>,
3829 T::Offset: UnwindOffset,
3830 {
3831 cie.offset = self.size() as _;
3832 let length = Label::new();
3833 let start = Label::new();
3834 let end = Label::new();
3835
3836 let section = match cie.format {
3837 Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff),
3838 Format::Dwarf64 => {
3839 let section = self.D32(0xffff_ffff);
3840 section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff)
3841 }
3842 };
3843
3844 let mut section = section.D8(cie.version);
3845
3846 if let Some(augmentation) = augmentation {
3847 section = section.append_bytes(augmentation.as_bytes());
3848 }
3849
3850 let section = section.D8(0);
3852
3853 let section = if T::has_address_and_segment_sizes(cie.version) {
3854 section.D8(cie.address_size).D8(0)
3855 } else {
3856 section
3857 };
3858
3859 let section = section
3860 .uleb(cie.code_alignment_factor)
3861 .sleb(cie.data_alignment_factor)
3862 .uleb(cie.return_address_register.0.into())
3863 .append_bytes(cie.initial_instructions.slice())
3864 .mark(&end);
3865
3866 cie.length = (&end - &start) as usize;
3867 length.set_const(cie.length as u64);
3868
3869 section
3870 }
3871
3872 fn fde<'a, 'input, E, T, L>(
3873 self,
3874 _kind: SectionKind<T>,
3875 cie_offset: L,
3876 fde: &mut FrameDescriptionEntry<EndianSlice<'input, E>>,
3877 ) -> Self
3878 where
3879 E: Endianity,
3880 T: UnwindSection<EndianSlice<'input, E>>,
3881 T::Offset: UnwindOffset,
3882 L: ToLabelOrNum<'a, u64>,
3883 {
3884 fde.offset = self.size() as _;
3885 let length = Label::new();
3886 let start = Label::new();
3887 let end = Label::new();
3888
3889 assert_eq!(fde.format, fde.cie.format);
3890
3891 let section = match T::cie_offset_encoding(fde.format) {
3892 CieOffsetEncoding::U32 => {
3893 let section = self.D32(&length).mark(&start);
3894 match cie_offset.to_labelornum() {
3895 LabelOrNum::Label(ref l) => section.D32(l),
3896 LabelOrNum::Num(o) => section.D32(o as u32),
3897 }
3898 }
3899 CieOffsetEncoding::U64 => {
3900 let section = self.D32(0xffff_ffff);
3901 section.D64(&length).mark(&start).D64(cie_offset)
3902 }
3903 };
3904
3905 let section = match fde.cie.address_size {
3906 4 => section
3907 .D32(fde.initial_address() as u32)
3908 .D32(fde.len() as u32),
3909 8 => section.D64(fde.initial_address()).D64(fde.len()),
3910 x => panic!("Unsupported address size: {}", x),
3911 };
3912
3913 let section = if let Some(ref augmentation) = fde.augmentation {
3914 let cie_aug = fde
3915 .cie
3916 .augmentation
3917 .expect("FDE has augmentation, but CIE doesn't");
3918
3919 if let Some(lsda) = augmentation.lsda {
3920 assert_eq!(
3922 cie_aug
3923 .lsda
3924 .expect("FDE has lsda, but CIE doesn't")
3925 .format(),
3926 constants::DW_EH_PE_absptr
3927 );
3928
3929 let section = section.uleb(u64::from(fde.cie.address_size));
3931 match fde.cie.address_size {
3932 4 => section.D32({
3933 let x: u64 = lsda.pointer();
3934 x as u32
3935 }),
3936 8 => section.D64({
3937 let x: u64 = lsda.pointer();
3938 x
3939 }),
3940 x => panic!("Unsupported address size: {}", x),
3941 }
3942 } else {
3943 section.uleb(0)
3946 }
3947 } else {
3948 section
3949 };
3950
3951 let section = section.append_bytes(fde.instructions.slice()).mark(&end);
3952
3953 fde.length = (&end - &start) as usize;
3954 length.set_const(fde.length as u64);
3955
3956 section
3957 }
3958 }
3959
3960 trait ResultExt {
3961 fn map_eof(self, input: &[u8]) -> Self;
3962 }
3963
3964 impl<T> ResultExt for Result<T> {
3965 fn map_eof(self, input: &[u8]) -> Self {
3966 match self {
3967 Err(Error::UnexpectedEof(id)) => {
3968 let id = ReaderOffsetId(id.0 - input.as_ptr() as u64);
3969 Err(Error::UnexpectedEof(id))
3970 }
3971 r => r,
3972 }
3973 }
3974 }
3975
3976 fn assert_parse_cie<'input, E>(
3977 kind: SectionKind<DebugFrame<EndianSlice<'input, E>>>,
3978 section: Section,
3979 address_size: u8,
3980 expected: Result<(
3981 EndianSlice<'input, E>,
3982 CommonInformationEntry<EndianSlice<'input, E>>,
3983 )>,
3984 ) where
3985 E: Endianity,
3986 {
3987 let section = section.get_contents().unwrap();
3988 let mut debug_frame = kind.section(§ion);
3989 debug_frame.set_address_size(address_size);
3990 let input = &mut EndianSlice::new(§ion, E::default());
3991 let bases = Default::default();
3992 let result = CommonInformationEntry::parse(&bases, &debug_frame, input);
3993 let result = result.map(|cie| (*input, cie)).map_eof(§ion);
3994 assert_eq!(result, expected);
3995 }
3996
3997 #[test]
3998 fn test_parse_cie_incomplete_length_32() {
3999 let kind = debug_frame_le();
4000 let section = Section::with_endian(kind.endian()).L16(5);
4001 assert_parse_cie(
4002 kind,
4003 section,
4004 8,
4005 Err(Error::UnexpectedEof(ReaderOffsetId(0))),
4006 );
4007 }
4008
4009 #[test]
4010 fn test_parse_cie_incomplete_length_64() {
4011 let kind = debug_frame_le();
4012 let section = Section::with_endian(kind.endian())
4013 .L32(0xffff_ffff)
4014 .L32(12345);
4015 assert_parse_cie(
4016 kind,
4017 section,
4018 8,
4019 Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4020 );
4021 }
4022
4023 #[test]
4024 fn test_parse_cie_incomplete_id_32() {
4025 let kind = debug_frame_be();
4026 let section = Section::with_endian(kind.endian())
4027 .B32(3)
4029 .B32(0xffff_ffff);
4030 assert_parse_cie(
4031 kind,
4032 section,
4033 8,
4034 Err(Error::UnexpectedEof(ReaderOffsetId(4))),
4035 );
4036 }
4037
4038 #[test]
4039 fn test_parse_cie_bad_id_32() {
4040 let kind = debug_frame_be();
4041 let section = Section::with_endian(kind.endian())
4042 .B32(4)
4044 .B32(0xbad1_bad2);
4046 assert_parse_cie(kind, section, 8, Err(Error::NotCieId));
4047 }
4048
4049 #[test]
4050 fn test_parse_cie_32_bad_version() {
4051 let mut cie = CommonInformationEntry {
4052 offset: 0,
4053 length: 0,
4054 format: Format::Dwarf32,
4055 version: 99,
4056 augmentation: None,
4057 address_size: 4,
4058 code_alignment_factor: 1,
4059 data_alignment_factor: 2,
4060 return_address_register: Register(3),
4061 initial_instructions: EndianSlice::new(&[], LittleEndian),
4062 };
4063
4064 let kind = debug_frame_le();
4065 let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4066 assert_parse_cie(kind, section, 4, Err(Error::UnknownVersion(99)));
4067 }
4068
4069 #[test]
4070 fn test_parse_cie_unknown_augmentation() {
4071 let length = Label::new();
4072 let start = Label::new();
4073 let end = Label::new();
4074
4075 let augmentation = "replicant";
4076 let expected_rest = [1, 2, 3];
4077
4078 let kind = debug_frame_le();
4079 let section = Section::with_endian(kind.endian())
4080 .L32(&length)
4082 .mark(&start)
4083 .L32(0xffff_ffff)
4085 .D8(4)
4087 .append_bytes(augmentation.as_bytes())
4089 .D8(0)
4091 .L32(1)
4093 .L32(2)
4094 .L32(3)
4095 .L32(4)
4096 .L32(5)
4097 .L32(6)
4098 .mark(&end)
4099 .append_bytes(&expected_rest);
4100
4101 let expected_length = (&end - &start) as u64;
4102 length.set_const(expected_length);
4103
4104 assert_parse_cie(kind, section, 8, Err(Error::UnknownAugmentation));
4105 }
4106
4107 fn test_parse_cie(format: Format, version: u8, address_size: u8) {
4108 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4109 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4110
4111 let mut cie = CommonInformationEntry {
4112 offset: 0,
4113 length: 0,
4114 format,
4115 version,
4116 augmentation: None,
4117 address_size,
4118 code_alignment_factor: 16,
4119 data_alignment_factor: 32,
4120 return_address_register: Register(1),
4121 initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4122 };
4123
4124 let kind = debug_frame_le();
4125 let section = Section::with_endian(kind.endian())
4126 .cie(kind, None, &mut cie)
4127 .append_bytes(&expected_rest);
4128
4129 assert_parse_cie(
4130 kind,
4131 section,
4132 address_size,
4133 Ok((EndianSlice::new(&expected_rest, LittleEndian), cie)),
4134 );
4135 }
4136
4137 #[test]
4138 fn test_parse_cie_32_ok() {
4139 test_parse_cie(Format::Dwarf32, 1, 4);
4140 test_parse_cie(Format::Dwarf32, 1, 8);
4141 test_parse_cie(Format::Dwarf32, 4, 4);
4142 test_parse_cie(Format::Dwarf32, 4, 8);
4143 }
4144
4145 #[test]
4146 fn test_parse_cie_64_ok() {
4147 test_parse_cie(Format::Dwarf64, 1, 4);
4148 test_parse_cie(Format::Dwarf64, 1, 8);
4149 test_parse_cie(Format::Dwarf64, 4, 4);
4150 test_parse_cie(Format::Dwarf64, 4, 8);
4151 }
4152
4153 #[test]
4154 fn test_parse_cie_length_too_big() {
4155 let expected_instrs: Vec<_> = (0..13).map(|_| constants::DW_CFA_nop.0).collect();
4156
4157 let mut cie = CommonInformationEntry {
4158 offset: 0,
4159 length: 0,
4160 format: Format::Dwarf32,
4161 version: 4,
4162 augmentation: None,
4163 address_size: 4,
4164 code_alignment_factor: 0,
4165 data_alignment_factor: 0,
4166 return_address_register: Register(3),
4167 initial_instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4168 };
4169
4170 let kind = debug_frame_le();
4171 let section = Section::with_endian(kind.endian()).cie(kind, None, &mut cie);
4172
4173 let mut contents = section.get_contents().unwrap();
4174
4175 contents[0] = 0;
4177 contents[1] = 0;
4178 contents[2] = 0;
4179 contents[3] = 255;
4180
4181 let debug_frame = DebugFrame::new(&contents, LittleEndian);
4182 let bases = Default::default();
4183 assert_eq!(
4184 CommonInformationEntry::parse(
4185 &bases,
4186 &debug_frame,
4187 &mut EndianSlice::new(&contents, LittleEndian)
4188 )
4189 .map_eof(&contents),
4190 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4191 );
4192 }
4193
4194 #[test]
4195 fn test_parse_fde_incomplete_length_32() {
4196 let kind = debug_frame_le();
4197 let section = Section::with_endian(kind.endian()).L16(5);
4198 let section = section.get_contents().unwrap();
4199 let debug_frame = kind.section(§ion);
4200 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4201 assert_eq!(
4202 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4203 Err(Error::UnexpectedEof(ReaderOffsetId(0)))
4204 );
4205 }
4206
4207 #[test]
4208 fn test_parse_fde_incomplete_length_64() {
4209 let kind = debug_frame_le();
4210 let section = Section::with_endian(kind.endian())
4211 .L32(0xffff_ffff)
4212 .L32(12345);
4213 let section = section.get_contents().unwrap();
4214 let debug_frame = kind.section(§ion);
4215 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4216 assert_eq!(
4217 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4218 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4219 );
4220 }
4221
4222 #[test]
4223 fn test_parse_fde_incomplete_cie_pointer_32() {
4224 let kind = debug_frame_be();
4225 let section = Section::with_endian(kind.endian())
4226 .B32(3)
4228 .B32(1994);
4229 let section = section.get_contents().unwrap();
4230 let debug_frame = kind.section(§ion);
4231 let rest = &mut EndianSlice::new(§ion, BigEndian);
4232 assert_eq!(
4233 parse_fde(debug_frame, rest, UnwindSection::cie_from_offset).map_eof(§ion),
4234 Err(Error::UnexpectedEof(ReaderOffsetId(4)))
4235 );
4236 }
4237
4238 #[test]
4239 fn test_parse_fde_32_ok() {
4240 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4241 let cie_offset = 0xbad0_bad1;
4242 let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4243
4244 let cie = CommonInformationEntry {
4245 offset: 0,
4246 length: 100,
4247 format: Format::Dwarf32,
4248 version: 4,
4249 augmentation: None,
4250 address_size: 8,
4252 code_alignment_factor: 3,
4253 data_alignment_factor: 2,
4254 return_address_register: Register(1),
4255 initial_instructions: EndianSlice::new(&[], LittleEndian),
4256 };
4257
4258 let mut fde = FrameDescriptionEntry {
4259 offset: 0,
4260 length: 0,
4261 format: Format::Dwarf32,
4262 cie: cie.clone(),
4263 initial_address: 0xfeed_beef,
4264 address_range: 39,
4265 augmentation: None,
4266 instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4267 };
4268
4269 let kind = debug_frame_le();
4270 let section = Section::with_endian(kind.endian())
4271 .fde(kind, cie_offset, &mut fde)
4272 .append_bytes(&expected_rest);
4273
4274 let section = section.get_contents().unwrap();
4275 let debug_frame = kind.section(§ion);
4276 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4277
4278 let get_cie = |_: &_, _: &_, offset| {
4279 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4280 Ok(cie.clone())
4281 };
4282
4283 assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4284 assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4285 }
4286
4287 #[test]
4288 fn test_parse_fde_64_ok() {
4289 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4290 let cie_offset = 0xbad0_bad1;
4291 let expected_instrs: Vec<_> = (0..7).map(|_| constants::DW_CFA_nop.0).collect();
4292
4293 let cie = CommonInformationEntry {
4294 offset: 0,
4295 length: 100,
4296 format: Format::Dwarf64,
4297 version: 4,
4298 augmentation: None,
4299 address_size: 8,
4300 code_alignment_factor: 3,
4301 data_alignment_factor: 2,
4302 return_address_register: Register(1),
4303 initial_instructions: EndianSlice::new(&[], LittleEndian),
4304 };
4305
4306 let mut fde = FrameDescriptionEntry {
4307 offset: 0,
4308 length: 0,
4309 format: Format::Dwarf64,
4310 cie: cie.clone(),
4311 initial_address: 0xfeed_beef,
4312 address_range: 999,
4313 augmentation: None,
4314 instructions: EndianSlice::new(&expected_instrs, LittleEndian),
4315 };
4316
4317 let kind = debug_frame_le();
4318 let section = Section::with_endian(kind.endian())
4319 .fde(kind, cie_offset, &mut fde)
4320 .append_bytes(&expected_rest);
4321
4322 let section = section.get_contents().unwrap();
4323 let debug_frame = kind.section(§ion);
4324 let rest = &mut EndianSlice::new(§ion, LittleEndian);
4325
4326 let get_cie = |_: &_, _: &_, offset| {
4327 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4328 Ok(cie.clone())
4329 };
4330
4331 assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde));
4332 assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian));
4333 }
4334
4335 #[test]
4336 fn test_parse_cfi_entry_on_cie_32_ok() {
4337 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4338 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4339
4340 let mut cie = CommonInformationEntry {
4341 offset: 0,
4342 length: 0,
4343 format: Format::Dwarf32,
4344 version: 4,
4345 augmentation: None,
4346 address_size: 4,
4347 code_alignment_factor: 16,
4348 data_alignment_factor: 32,
4349 return_address_register: Register(1),
4350 initial_instructions: EndianSlice::new(&expected_instrs, BigEndian),
4351 };
4352
4353 let kind = debug_frame_be();
4354 let section = Section::with_endian(kind.endian())
4355 .cie(kind, None, &mut cie)
4356 .append_bytes(&expected_rest);
4357 let section = section.get_contents().unwrap();
4358 let debug_frame = kind.section(§ion);
4359 let rest = &mut EndianSlice::new(§ion, BigEndian);
4360
4361 let bases = Default::default();
4362 assert_eq!(
4363 parse_cfi_entry(&bases, &debug_frame, rest),
4364 Ok(Some(CieOrFde::Cie(cie)))
4365 );
4366 assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4367 }
4368
4369 #[test]
4370 fn test_parse_cfi_entry_on_fde_32_ok() {
4371 let cie_offset = 0x1234_5678;
4372 let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4373 let expected_instrs: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4374
4375 let cie = CommonInformationEntry {
4376 offset: 0,
4377 length: 0,
4378 format: Format::Dwarf32,
4379 version: 4,
4380 augmentation: None,
4381 address_size: 4,
4382 code_alignment_factor: 16,
4383 data_alignment_factor: 32,
4384 return_address_register: Register(1),
4385 initial_instructions: EndianSlice::new(&[], BigEndian),
4386 };
4387
4388 let mut fde = FrameDescriptionEntry {
4389 offset: 0,
4390 length: 0,
4391 format: Format::Dwarf32,
4392 cie: cie.clone(),
4393 initial_address: 0xfeed_beef,
4394 address_range: 39,
4395 augmentation: None,
4396 instructions: EndianSlice::new(&expected_instrs, BigEndian),
4397 };
4398
4399 let kind = debug_frame_be();
4400 let section = Section::with_endian(kind.endian())
4401 .fde(kind, cie_offset, &mut fde)
4402 .append_bytes(&expected_rest);
4403
4404 let section = section.get_contents().unwrap();
4405 let debug_frame = kind.section(§ion);
4406 let rest = &mut EndianSlice::new(§ion, BigEndian);
4407
4408 let bases = Default::default();
4409 match parse_cfi_entry(&bases, &debug_frame, rest) {
4410 Ok(Some(CieOrFde::Fde(partial))) => {
4411 assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
4412
4413 assert_eq!(partial.length, fde.length);
4414 assert_eq!(partial.format, fde.format);
4415 assert_eq!(partial.cie_offset, DebugFrameOffset(cie_offset as usize));
4416
4417 let get_cie = |_: &_, _: &_, offset| {
4418 assert_eq!(offset, DebugFrameOffset(cie_offset as usize));
4419 Ok(cie.clone())
4420 };
4421
4422 assert_eq!(partial.parse(get_cie), Ok(fde));
4423 }
4424 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4425 }
4426 }
4427
4428 #[test]
4429 fn test_cfi_entries_iter() {
4430 let expected_instrs1: Vec<_> = (0..4).map(|_| constants::DW_CFA_nop.0).collect();
4431
4432 let expected_instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
4433
4434 let expected_instrs3: Vec<_> = (0..12).map(|_| constants::DW_CFA_nop.0).collect();
4435
4436 let expected_instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
4437
4438 let mut cie1 = CommonInformationEntry {
4439 offset: 0,
4440 length: 0,
4441 format: Format::Dwarf32,
4442 version: 4,
4443 augmentation: None,
4444 address_size: 4,
4445 code_alignment_factor: 1,
4446 data_alignment_factor: 2,
4447 return_address_register: Register(3),
4448 initial_instructions: EndianSlice::new(&expected_instrs1, BigEndian),
4449 };
4450
4451 let mut cie2 = CommonInformationEntry {
4452 offset: 0,
4453 length: 0,
4454 format: Format::Dwarf32,
4455 version: 4,
4456 augmentation: None,
4457 address_size: 4,
4458 code_alignment_factor: 3,
4459 data_alignment_factor: 2,
4460 return_address_register: Register(1),
4461 initial_instructions: EndianSlice::new(&expected_instrs2, BigEndian),
4462 };
4463
4464 let cie1_location = Label::new();
4465 let cie2_location = Label::new();
4466
4467 let kind = debug_frame_be();
4471 let section = Section::with_endian(kind.endian())
4472 .mark(&cie1_location)
4473 .cie(kind, None, &mut cie1)
4474 .mark(&cie2_location)
4475 .cie(kind, None, &mut cie2);
4476
4477 let mut fde1 = FrameDescriptionEntry {
4478 offset: 0,
4479 length: 0,
4480 format: Format::Dwarf32,
4481 cie: cie1.clone(),
4482 initial_address: 0xfeed_beef,
4483 address_range: 39,
4484 augmentation: None,
4485 instructions: EndianSlice::new(&expected_instrs3, BigEndian),
4486 };
4487
4488 let mut fde2 = FrameDescriptionEntry {
4489 offset: 0,
4490 length: 0,
4491 format: Format::Dwarf32,
4492 cie: cie2.clone(),
4493 initial_address: 0xfeed_face,
4494 address_range: 9000,
4495 augmentation: None,
4496 instructions: EndianSlice::new(&expected_instrs4, BigEndian),
4497 };
4498
4499 let section =
4500 section
4501 .fde(kind, &cie1_location, &mut fde1)
4502 .fde(kind, &cie2_location, &mut fde2);
4503
4504 section.start().set_const(0);
4505
4506 let cie1_offset = cie1_location.value().unwrap() as usize;
4507 let cie2_offset = cie2_location.value().unwrap() as usize;
4508
4509 let contents = section.get_contents().unwrap();
4510 let debug_frame = kind.section(&contents);
4511
4512 let bases = Default::default();
4513 let mut entries = debug_frame.entries(&bases);
4514
4515 assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie1.clone()))));
4516 assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie2.clone()))));
4517
4518 match entries.next() {
4519 Ok(Some(CieOrFde::Fde(partial))) => {
4520 assert_eq!(partial.length, fde1.length);
4521 assert_eq!(partial.format, fde1.format);
4522 assert_eq!(partial.cie_offset, DebugFrameOffset(cie1_offset));
4523
4524 let get_cie = |_: &_, _: &_, offset| {
4525 assert_eq!(offset, DebugFrameOffset(cie1_offset));
4526 Ok(cie1.clone())
4527 };
4528 assert_eq!(partial.parse(get_cie), Ok(fde1));
4529 }
4530 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4531 }
4532
4533 match entries.next() {
4534 Ok(Some(CieOrFde::Fde(partial))) => {
4535 assert_eq!(partial.length, fde2.length);
4536 assert_eq!(partial.format, fde2.format);
4537 assert_eq!(partial.cie_offset, DebugFrameOffset(cie2_offset));
4538
4539 let get_cie = |_: &_, _: &_, offset| {
4540 assert_eq!(offset, DebugFrameOffset(cie2_offset));
4541 Ok(cie2.clone())
4542 };
4543 assert_eq!(partial.parse(get_cie), Ok(fde2));
4544 }
4545 otherwise => panic!("Unexpected result: {:#?}", otherwise),
4546 }
4547
4548 assert_eq!(entries.next(), Ok(None));
4549 }
4550
4551 #[test]
4552 fn test_parse_cie_from_offset() {
4553 let filler = [1, 2, 3, 4, 5, 6, 7, 8, 9];
4554 let instrs: Vec<_> = (0..5).map(|_| constants::DW_CFA_nop.0).collect();
4555
4556 let mut cie = CommonInformationEntry {
4557 offset: 0,
4558 length: 0,
4559 format: Format::Dwarf64,
4560 version: 4,
4561 augmentation: None,
4562 address_size: 4,
4563 code_alignment_factor: 4,
4564 data_alignment_factor: 8,
4565 return_address_register: Register(12),
4566 initial_instructions: EndianSlice::new(&instrs, LittleEndian),
4567 };
4568
4569 let cie_location = Label::new();
4570
4571 let kind = debug_frame_le();
4572 let section = Section::with_endian(kind.endian())
4573 .append_bytes(&filler)
4574 .mark(&cie_location)
4575 .cie(kind, None, &mut cie)
4576 .append_bytes(&filler);
4577
4578 section.start().set_const(0);
4579
4580 let cie_offset = DebugFrameOffset(cie_location.value().unwrap() as usize);
4581
4582 let contents = section.get_contents().unwrap();
4583 let debug_frame = kind.section(&contents);
4584 let bases = Default::default();
4585
4586 assert_eq!(debug_frame.cie_from_offset(&bases, cie_offset), Ok(cie));
4587 }
4588
4589 fn parse_cfi_instruction<R: Reader + Default>(
4590 input: &mut R,
4591 address_size: u8,
4592 ) -> Result<CallFrameInstruction<R::Offset>> {
4593 let section = input.clone();
4594 let parameters = &PointerEncodingParameters {
4595 bases: &SectionBaseAddresses::default(),
4596 func_base: None,
4597 address_size,
4598 section: §ion,
4599 };
4600 CallFrameInstruction::parse(input, None, parameters, Vendor::Default)
4601 }
4602
4603 #[test]
4604 fn test_parse_cfi_instruction_advance_loc() {
4605 let expected_rest = [1, 2, 3, 4];
4606 let expected_delta = 42;
4607 let section = Section::with_endian(Endian::Little)
4608 .D8(constants::DW_CFA_advance_loc.0 | expected_delta)
4609 .append_bytes(&expected_rest);
4610 let contents = section.get_contents().unwrap();
4611 let input = &mut EndianSlice::new(&contents, LittleEndian);
4612 assert_eq!(
4613 parse_cfi_instruction(input, 8),
4614 Ok(CallFrameInstruction::AdvanceLoc {
4615 delta: u32::from(expected_delta),
4616 })
4617 );
4618 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4619 }
4620
4621 #[test]
4622 fn test_parse_cfi_instruction_offset() {
4623 let expected_rest = [1, 2, 3, 4];
4624 let expected_reg = 3;
4625 let expected_offset = 1997;
4626 let section = Section::with_endian(Endian::Little)
4627 .D8(constants::DW_CFA_offset.0 | expected_reg)
4628 .uleb(expected_offset)
4629 .append_bytes(&expected_rest);
4630 let contents = section.get_contents().unwrap();
4631 let input = &mut EndianSlice::new(&contents, LittleEndian);
4632 assert_eq!(
4633 parse_cfi_instruction(input, 8),
4634 Ok(CallFrameInstruction::Offset {
4635 register: Register(expected_reg.into()),
4636 factored_offset: expected_offset,
4637 })
4638 );
4639 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4640 }
4641
4642 #[test]
4643 fn test_parse_cfi_instruction_restore() {
4644 let expected_rest = [1, 2, 3, 4];
4645 let expected_reg = 3;
4646 let section = Section::with_endian(Endian::Little)
4647 .D8(constants::DW_CFA_restore.0 | expected_reg)
4648 .append_bytes(&expected_rest);
4649 let contents = section.get_contents().unwrap();
4650 let input = &mut EndianSlice::new(&contents, LittleEndian);
4651 assert_eq!(
4652 parse_cfi_instruction(input, 8),
4653 Ok(CallFrameInstruction::Restore {
4654 register: Register(expected_reg.into()),
4655 })
4656 );
4657 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4658 }
4659
4660 #[test]
4661 fn test_parse_cfi_instruction_nop() {
4662 let expected_rest = [1, 2, 3, 4];
4663 let section = Section::with_endian(Endian::Little)
4664 .D8(constants::DW_CFA_nop.0)
4665 .append_bytes(&expected_rest);
4666 let contents = section.get_contents().unwrap();
4667 let input = &mut EndianSlice::new(&contents, LittleEndian);
4668 assert_eq!(
4669 parse_cfi_instruction(input, 8),
4670 Ok(CallFrameInstruction::Nop)
4671 );
4672 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4673 }
4674
4675 #[test]
4676 fn test_parse_cfi_instruction_set_loc() {
4677 let expected_rest = [1, 2, 3, 4];
4678 let expected_addr = 0xdead_beef;
4679 let section = Section::with_endian(Endian::Little)
4680 .D8(constants::DW_CFA_set_loc.0)
4681 .L64(expected_addr)
4682 .append_bytes(&expected_rest);
4683 let contents = section.get_contents().unwrap();
4684 let input = &mut EndianSlice::new(&contents, LittleEndian);
4685 assert_eq!(
4686 parse_cfi_instruction(input, 8),
4687 Ok(CallFrameInstruction::SetLoc {
4688 address: expected_addr,
4689 })
4690 );
4691 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4692 }
4693
4694 #[test]
4695 fn test_parse_cfi_instruction_set_loc_encoding() {
4696 let text_base = 0xfeed_face;
4697 let addr_offset = 0xbeef;
4698 let expected_addr = text_base + addr_offset;
4699 let expected_rest = [1, 2, 3, 4];
4700 let section = Section::with_endian(Endian::Little)
4701 .D8(constants::DW_CFA_set_loc.0)
4702 .L64(addr_offset)
4703 .append_bytes(&expected_rest);
4704 let contents = section.get_contents().unwrap();
4705 let input = &mut EndianSlice::new(&contents, LittleEndian);
4706 let parameters = &PointerEncodingParameters {
4707 bases: &BaseAddresses::default().set_text(text_base).eh_frame,
4708 func_base: None,
4709 address_size: 8,
4710 section: &EndianSlice::new(&[], LittleEndian),
4711 };
4712 assert_eq!(
4713 CallFrameInstruction::parse(
4714 input,
4715 Some(constants::DW_EH_PE_textrel),
4716 parameters,
4717 Vendor::Default
4718 ),
4719 Ok(CallFrameInstruction::SetLoc {
4720 address: expected_addr,
4721 })
4722 );
4723 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4724 }
4725
4726 #[test]
4727 fn test_parse_cfi_instruction_advance_loc1() {
4728 let expected_rest = [1, 2, 3, 4];
4729 let expected_delta = 8;
4730 let section = Section::with_endian(Endian::Little)
4731 .D8(constants::DW_CFA_advance_loc1.0)
4732 .D8(expected_delta)
4733 .append_bytes(&expected_rest);
4734 let contents = section.get_contents().unwrap();
4735 let input = &mut EndianSlice::new(&contents, LittleEndian);
4736 assert_eq!(
4737 parse_cfi_instruction(input, 8),
4738 Ok(CallFrameInstruction::AdvanceLoc {
4739 delta: u32::from(expected_delta),
4740 })
4741 );
4742 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4743 }
4744
4745 #[test]
4746 fn test_parse_cfi_instruction_advance_loc2() {
4747 let expected_rest = [1, 2, 3, 4];
4748 let expected_delta = 500;
4749 let section = Section::with_endian(Endian::Little)
4750 .D8(constants::DW_CFA_advance_loc2.0)
4751 .L16(expected_delta)
4752 .append_bytes(&expected_rest);
4753 let contents = section.get_contents().unwrap();
4754 let input = &mut EndianSlice::new(&contents, LittleEndian);
4755 assert_eq!(
4756 parse_cfi_instruction(input, 8),
4757 Ok(CallFrameInstruction::AdvanceLoc {
4758 delta: u32::from(expected_delta),
4759 })
4760 );
4761 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4762 }
4763
4764 #[test]
4765 fn test_parse_cfi_instruction_advance_loc4() {
4766 let expected_rest = [1, 2, 3, 4];
4767 let expected_delta = 1 << 20;
4768 let section = Section::with_endian(Endian::Little)
4769 .D8(constants::DW_CFA_advance_loc4.0)
4770 .L32(expected_delta)
4771 .append_bytes(&expected_rest);
4772 let contents = section.get_contents().unwrap();
4773 let input = &mut EndianSlice::new(&contents, LittleEndian);
4774 assert_eq!(
4775 parse_cfi_instruction(input, 8),
4776 Ok(CallFrameInstruction::AdvanceLoc {
4777 delta: expected_delta,
4778 })
4779 );
4780 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4781 }
4782
4783 #[test]
4784 fn test_parse_cfi_instruction_offset_extended() {
4785 let expected_rest = [1, 2, 3, 4];
4786 let expected_reg = 7;
4787 let expected_offset = 33;
4788 let section = Section::with_endian(Endian::Little)
4789 .D8(constants::DW_CFA_offset_extended.0)
4790 .uleb(expected_reg.into())
4791 .uleb(expected_offset)
4792 .append_bytes(&expected_rest);
4793 let contents = section.get_contents().unwrap();
4794 let input = &mut EndianSlice::new(&contents, LittleEndian);
4795 assert_eq!(
4796 parse_cfi_instruction(input, 8),
4797 Ok(CallFrameInstruction::Offset {
4798 register: Register(expected_reg),
4799 factored_offset: expected_offset,
4800 })
4801 );
4802 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4803 }
4804
4805 #[test]
4806 fn test_parse_cfi_instruction_restore_extended() {
4807 let expected_rest = [1, 2, 3, 4];
4808 let expected_reg = 7;
4809 let section = Section::with_endian(Endian::Little)
4810 .D8(constants::DW_CFA_restore_extended.0)
4811 .uleb(expected_reg.into())
4812 .append_bytes(&expected_rest);
4813 let contents = section.get_contents().unwrap();
4814 let input = &mut EndianSlice::new(&contents, LittleEndian);
4815 assert_eq!(
4816 parse_cfi_instruction(input, 8),
4817 Ok(CallFrameInstruction::Restore {
4818 register: Register(expected_reg),
4819 })
4820 );
4821 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4822 }
4823
4824 #[test]
4825 fn test_parse_cfi_instruction_undefined() {
4826 let expected_rest = [1, 2, 3, 4];
4827 let expected_reg = 7;
4828 let section = Section::with_endian(Endian::Little)
4829 .D8(constants::DW_CFA_undefined.0)
4830 .uleb(expected_reg.into())
4831 .append_bytes(&expected_rest);
4832 let contents = section.get_contents().unwrap();
4833 let input = &mut EndianSlice::new(&contents, LittleEndian);
4834 assert_eq!(
4835 parse_cfi_instruction(input, 8),
4836 Ok(CallFrameInstruction::Undefined {
4837 register: Register(expected_reg),
4838 })
4839 );
4840 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4841 }
4842
4843 #[test]
4844 fn test_parse_cfi_instruction_same_value() {
4845 let expected_rest = [1, 2, 3, 4];
4846 let expected_reg = 7;
4847 let section = Section::with_endian(Endian::Little)
4848 .D8(constants::DW_CFA_same_value.0)
4849 .uleb(expected_reg.into())
4850 .append_bytes(&expected_rest);
4851 let contents = section.get_contents().unwrap();
4852 let input = &mut EndianSlice::new(&contents, LittleEndian);
4853 assert_eq!(
4854 parse_cfi_instruction(input, 8),
4855 Ok(CallFrameInstruction::SameValue {
4856 register: Register(expected_reg),
4857 })
4858 );
4859 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4860 }
4861
4862 #[test]
4863 fn test_parse_cfi_instruction_register() {
4864 let expected_rest = [1, 2, 3, 4];
4865 let expected_dest_reg = 7;
4866 let expected_src_reg = 8;
4867 let section = Section::with_endian(Endian::Little)
4868 .D8(constants::DW_CFA_register.0)
4869 .uleb(expected_dest_reg.into())
4870 .uleb(expected_src_reg.into())
4871 .append_bytes(&expected_rest);
4872 let contents = section.get_contents().unwrap();
4873 let input = &mut EndianSlice::new(&contents, LittleEndian);
4874 assert_eq!(
4875 parse_cfi_instruction(input, 8),
4876 Ok(CallFrameInstruction::Register {
4877 dest_register: Register(expected_dest_reg),
4878 src_register: Register(expected_src_reg),
4879 })
4880 );
4881 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4882 }
4883
4884 #[test]
4885 fn test_parse_cfi_instruction_remember_state() {
4886 let expected_rest = [1, 2, 3, 4];
4887 let section = Section::with_endian(Endian::Little)
4888 .D8(constants::DW_CFA_remember_state.0)
4889 .append_bytes(&expected_rest);
4890 let contents = section.get_contents().unwrap();
4891 let input = &mut EndianSlice::new(&contents, LittleEndian);
4892 assert_eq!(
4893 parse_cfi_instruction(input, 8),
4894 Ok(CallFrameInstruction::RememberState)
4895 );
4896 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4897 }
4898
4899 #[test]
4900 fn test_parse_cfi_instruction_restore_state() {
4901 let expected_rest = [1, 2, 3, 4];
4902 let section = Section::with_endian(Endian::Little)
4903 .D8(constants::DW_CFA_restore_state.0)
4904 .append_bytes(&expected_rest);
4905 let contents = section.get_contents().unwrap();
4906 let input = &mut EndianSlice::new(&contents, LittleEndian);
4907 assert_eq!(
4908 parse_cfi_instruction(input, 8),
4909 Ok(CallFrameInstruction::RestoreState)
4910 );
4911 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4912 }
4913
4914 #[test]
4915 fn test_parse_cfi_instruction_def_cfa() {
4916 let expected_rest = [1, 2, 3, 4];
4917 let expected_reg = 2;
4918 let expected_offset = 0;
4919 let section = Section::with_endian(Endian::Little)
4920 .D8(constants::DW_CFA_def_cfa.0)
4921 .uleb(expected_reg.into())
4922 .uleb(expected_offset)
4923 .append_bytes(&expected_rest);
4924 let contents = section.get_contents().unwrap();
4925 let input = &mut EndianSlice::new(&contents, LittleEndian);
4926 assert_eq!(
4927 parse_cfi_instruction(input, 8),
4928 Ok(CallFrameInstruction::DefCfa {
4929 register: Register(expected_reg),
4930 offset: expected_offset,
4931 })
4932 );
4933 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4934 }
4935
4936 #[test]
4937 fn test_parse_cfi_instruction_def_cfa_register() {
4938 let expected_rest = [1, 2, 3, 4];
4939 let expected_reg = 2;
4940 let section = Section::with_endian(Endian::Little)
4941 .D8(constants::DW_CFA_def_cfa_register.0)
4942 .uleb(expected_reg.into())
4943 .append_bytes(&expected_rest);
4944 let contents = section.get_contents().unwrap();
4945 let input = &mut EndianSlice::new(&contents, LittleEndian);
4946 assert_eq!(
4947 parse_cfi_instruction(input, 8),
4948 Ok(CallFrameInstruction::DefCfaRegister {
4949 register: Register(expected_reg),
4950 })
4951 );
4952 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4953 }
4954
4955 #[test]
4956 fn test_parse_cfi_instruction_def_cfa_offset() {
4957 let expected_rest = [1, 2, 3, 4];
4958 let expected_offset = 23;
4959 let section = Section::with_endian(Endian::Little)
4960 .D8(constants::DW_CFA_def_cfa_offset.0)
4961 .uleb(expected_offset)
4962 .append_bytes(&expected_rest);
4963 let contents = section.get_contents().unwrap();
4964 let input = &mut EndianSlice::new(&contents, LittleEndian);
4965 assert_eq!(
4966 parse_cfi_instruction(input, 8),
4967 Ok(CallFrameInstruction::DefCfaOffset {
4968 offset: expected_offset,
4969 })
4970 );
4971 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
4972 }
4973
4974 #[test]
4975 fn test_parse_cfi_instruction_def_cfa_expression() {
4976 let expected_rest = [1, 2, 3, 4];
4977 let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
4978
4979 let length = Label::new();
4980 let start = Label::new();
4981 let end = Label::new();
4982
4983 let section = Section::with_endian(Endian::Little)
4984 .D8(constants::DW_CFA_def_cfa_expression.0)
4985 .D8(&length)
4986 .mark(&start)
4987 .append_bytes(&expected_expr)
4988 .mark(&end)
4989 .append_bytes(&expected_rest);
4990
4991 length.set_const((&end - &start) as u64);
4992 let expected_expression = UnwindExpression {
4993 offset: (&start - §ion.start()) as usize,
4994 length: (&end - &start) as usize,
4995 };
4996 let contents = section.get_contents().unwrap();
4997 let input = &mut EndianSlice::new(&contents, LittleEndian);
4998
4999 assert_eq!(
5000 parse_cfi_instruction(input, 8),
5001 Ok(CallFrameInstruction::DefCfaExpression {
5002 expression: expected_expression,
5003 })
5004 );
5005 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5006 }
5007
5008 #[test]
5009 fn test_parse_cfi_instruction_expression() {
5010 let expected_rest = [1, 2, 3, 4];
5011 let expected_reg = 99;
5012 let expected_expr = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
5013
5014 let length = Label::new();
5015 let start = Label::new();
5016 let end = Label::new();
5017
5018 let section = Section::with_endian(Endian::Little)
5019 .D8(constants::DW_CFA_expression.0)
5020 .uleb(expected_reg.into())
5021 .D8(&length)
5022 .mark(&start)
5023 .append_bytes(&expected_expr)
5024 .mark(&end)
5025 .append_bytes(&expected_rest);
5026
5027 length.set_const((&end - &start) as u64);
5028 let expected_expression = UnwindExpression {
5029 offset: (&start - §ion.start()) as usize,
5030 length: (&end - &start) as usize,
5031 };
5032 let contents = section.get_contents().unwrap();
5033 let input = &mut EndianSlice::new(&contents, LittleEndian);
5034
5035 assert_eq!(
5036 parse_cfi_instruction(input, 8),
5037 Ok(CallFrameInstruction::Expression {
5038 register: Register(expected_reg),
5039 expression: expected_expression,
5040 })
5041 );
5042 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5043 }
5044
5045 #[test]
5046 fn test_parse_cfi_instruction_offset_extended_sf() {
5047 let expected_rest = [1, 2, 3, 4];
5048 let expected_reg = 7;
5049 let expected_offset = -33;
5050 let section = Section::with_endian(Endian::Little)
5051 .D8(constants::DW_CFA_offset_extended_sf.0)
5052 .uleb(expected_reg.into())
5053 .sleb(expected_offset)
5054 .append_bytes(&expected_rest);
5055 let contents = section.get_contents().unwrap();
5056 let input = &mut EndianSlice::new(&contents, LittleEndian);
5057 assert_eq!(
5058 parse_cfi_instruction(input, 8),
5059 Ok(CallFrameInstruction::OffsetExtendedSf {
5060 register: Register(expected_reg),
5061 factored_offset: expected_offset,
5062 })
5063 );
5064 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5065 }
5066
5067 #[test]
5068 fn test_parse_cfi_instruction_def_cfa_sf() {
5069 let expected_rest = [1, 2, 3, 4];
5070 let expected_reg = 2;
5071 let expected_offset = -9999;
5072 let section = Section::with_endian(Endian::Little)
5073 .D8(constants::DW_CFA_def_cfa_sf.0)
5074 .uleb(expected_reg.into())
5075 .sleb(expected_offset)
5076 .append_bytes(&expected_rest);
5077 let contents = section.get_contents().unwrap();
5078 let input = &mut EndianSlice::new(&contents, LittleEndian);
5079 assert_eq!(
5080 parse_cfi_instruction(input, 8),
5081 Ok(CallFrameInstruction::DefCfaSf {
5082 register: Register(expected_reg),
5083 factored_offset: expected_offset,
5084 })
5085 );
5086 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5087 }
5088
5089 #[test]
5090 fn test_parse_cfi_instruction_def_cfa_offset_sf() {
5091 let expected_rest = [1, 2, 3, 4];
5092 let expected_offset = -123;
5093 let section = Section::with_endian(Endian::Little)
5094 .D8(constants::DW_CFA_def_cfa_offset_sf.0)
5095 .sleb(expected_offset)
5096 .append_bytes(&expected_rest);
5097 let contents = section.get_contents().unwrap();
5098 let input = &mut EndianSlice::new(&contents, LittleEndian);
5099 assert_eq!(
5100 parse_cfi_instruction(input, 8),
5101 Ok(CallFrameInstruction::DefCfaOffsetSf {
5102 factored_offset: expected_offset,
5103 })
5104 );
5105 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5106 }
5107
5108 #[test]
5109 fn test_parse_cfi_instruction_val_offset() {
5110 let expected_rest = [1, 2, 3, 4];
5111 let expected_reg = 50;
5112 let expected_offset = 23;
5113 let section = Section::with_endian(Endian::Little)
5114 .D8(constants::DW_CFA_val_offset.0)
5115 .uleb(expected_reg.into())
5116 .uleb(expected_offset)
5117 .append_bytes(&expected_rest);
5118 let contents = section.get_contents().unwrap();
5119 let input = &mut EndianSlice::new(&contents, LittleEndian);
5120 assert_eq!(
5121 parse_cfi_instruction(input, 8),
5122 Ok(CallFrameInstruction::ValOffset {
5123 register: Register(expected_reg),
5124 factored_offset: expected_offset,
5125 })
5126 );
5127 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5128 }
5129
5130 #[test]
5131 fn test_parse_cfi_instruction_val_offset_sf() {
5132 let expected_rest = [1, 2, 3, 4];
5133 let expected_reg = 50;
5134 let expected_offset = -23;
5135 let section = Section::with_endian(Endian::Little)
5136 .D8(constants::DW_CFA_val_offset_sf.0)
5137 .uleb(expected_reg.into())
5138 .sleb(expected_offset)
5139 .append_bytes(&expected_rest);
5140 let contents = section.get_contents().unwrap();
5141 let input = &mut EndianSlice::new(&contents, LittleEndian);
5142 assert_eq!(
5143 parse_cfi_instruction(input, 8),
5144 Ok(CallFrameInstruction::ValOffsetSf {
5145 register: Register(expected_reg),
5146 factored_offset: expected_offset,
5147 })
5148 );
5149 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5150 }
5151
5152 #[test]
5153 fn test_parse_cfi_instruction_val_expression() {
5154 let expected_rest = [1, 2, 3, 4];
5155 let expected_reg = 50;
5156 let expected_expr = [2, 2, 1, 1, 5, 5];
5157
5158 let length = Label::new();
5159 let start = Label::new();
5160 let end = Label::new();
5161
5162 let section = Section::with_endian(Endian::Little)
5163 .D8(constants::DW_CFA_val_expression.0)
5164 .uleb(expected_reg.into())
5165 .D8(&length)
5166 .mark(&start)
5167 .append_bytes(&expected_expr)
5168 .mark(&end)
5169 .append_bytes(&expected_rest);
5170
5171 length.set_const((&end - &start) as u64);
5172 let expected_expression = UnwindExpression {
5173 offset: (&start - §ion.start()) as usize,
5174 length: (&end - &start) as usize,
5175 };
5176 let contents = section.get_contents().unwrap();
5177 let input = &mut EndianSlice::new(&contents, LittleEndian);
5178
5179 assert_eq!(
5180 parse_cfi_instruction(input, 8),
5181 Ok(CallFrameInstruction::ValExpression {
5182 register: Register(expected_reg),
5183 expression: expected_expression,
5184 })
5185 );
5186 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5187 }
5188
5189 #[test]
5190 fn test_parse_cfi_instruction_negate_ra_state() {
5191 let expected_rest = [1, 2, 3, 4];
5192 let section = Section::with_endian(Endian::Little)
5193 .D8(constants::DW_CFA_AARCH64_negate_ra_state.0)
5194 .append_bytes(&expected_rest);
5195 let contents = section.get_contents().unwrap();
5196 let input = &mut EndianSlice::new(&contents, LittleEndian);
5197 let parameters = &PointerEncodingParameters {
5198 bases: &SectionBaseAddresses::default(),
5199 func_base: None,
5200 address_size: 8,
5201 section: &EndianSlice::default(),
5202 };
5203 assert_eq!(
5204 CallFrameInstruction::parse(input, None, parameters, Vendor::AArch64),
5205 Ok(CallFrameInstruction::NegateRaState)
5206 );
5207 assert_eq!(*input, EndianSlice::new(&expected_rest, LittleEndian));
5208 }
5209
5210 #[test]
5211 fn test_parse_cfi_instruction_unknown_instruction() {
5212 let expected_rest = [1, 2, 3, 4];
5213 let unknown_instr = constants::DwCfa(0b0011_1111);
5214 let section = Section::with_endian(Endian::Little)
5215 .D8(unknown_instr.0)
5216 .append_bytes(&expected_rest);
5217 let contents = section.get_contents().unwrap();
5218 let input = &mut EndianSlice::new(&contents, LittleEndian);
5219 assert_eq!(
5220 parse_cfi_instruction(input, 8),
5221 Err(Error::UnknownCallFrameInstruction(unknown_instr))
5222 );
5223 }
5224
5225 #[test]
5226 fn test_call_frame_instruction_iter_ok() {
5227 let expected_reg = 50;
5228 let expected_expr = [2, 2, 1, 1, 5, 5];
5229 let expected_delta = 230;
5230
5231 let length = Label::new();
5232 let start = Label::new();
5233 let end = Label::new();
5234
5235 let section = Section::with_endian(Endian::Big)
5236 .D8(constants::DW_CFA_val_expression.0)
5237 .uleb(expected_reg.into())
5238 .D8(&length)
5239 .mark(&start)
5240 .append_bytes(&expected_expr)
5241 .mark(&end)
5242 .D8(constants::DW_CFA_advance_loc1.0)
5243 .D8(expected_delta);
5244
5245 length.set_const((&end - &start) as u64);
5246 let expected_expression = UnwindExpression {
5247 offset: (&start - §ion.start()) as usize,
5248 length: (&end - &start) as usize,
5249 };
5250 let contents = section.get_contents().unwrap();
5251 let input = EndianSlice::new(&contents, BigEndian);
5252 let parameters = PointerEncodingParameters {
5253 bases: &SectionBaseAddresses::default(),
5254 func_base: None,
5255 address_size: 8,
5256 section: &input,
5257 };
5258 let mut iter = CallFrameInstructionIter {
5259 input,
5260 address_encoding: None,
5261 parameters,
5262 vendor: Vendor::Default,
5263 };
5264
5265 assert_eq!(
5266 iter.next(),
5267 Ok(Some(CallFrameInstruction::ValExpression {
5268 register: Register(expected_reg),
5269 expression: expected_expression,
5270 }))
5271 );
5272
5273 assert_eq!(
5274 iter.next(),
5275 Ok(Some(CallFrameInstruction::AdvanceLoc {
5276 delta: u32::from(expected_delta),
5277 }))
5278 );
5279
5280 assert_eq!(iter.next(), Ok(None));
5281 }
5282
5283 #[test]
5284 fn test_call_frame_instruction_iter_err() {
5285 let section = Section::with_endian(Endian::Big).D8(constants::DW_CFA_advance_loc1.0);
5287
5288 let contents = section.get_contents().unwrap();
5289 let input = EndianSlice::new(&contents, BigEndian);
5290 let parameters = PointerEncodingParameters {
5291 bases: &SectionBaseAddresses::default(),
5292 func_base: None,
5293 address_size: 8,
5294 section: &EndianSlice::default(),
5295 };
5296 let mut iter = CallFrameInstructionIter {
5297 input,
5298 address_encoding: None,
5299 parameters,
5300 vendor: Vendor::Default,
5301 };
5302
5303 assert_eq!(
5304 iter.next().map_eof(&contents),
5305 Err(Error::UnexpectedEof(ReaderOffsetId(1)))
5306 );
5307 assert_eq!(iter.next(), Ok(None));
5308 }
5309
5310 fn assert_eval<'a, I>(
5311 mut initial_ctx: UnwindContext<usize>,
5312 expected_ctx: UnwindContext<usize>,
5313 cie: CommonInformationEntry<EndianSlice<'a, LittleEndian>>,
5314 fde: Option<FrameDescriptionEntry<EndianSlice<'a, LittleEndian>>>,
5315 instructions: I,
5316 ) where
5317 I: AsRef<[(Result<bool>, CallFrameInstruction<usize>)]>,
5318 {
5319 {
5320 let section = &DebugFrame::from(EndianSlice::default());
5321 let bases = &BaseAddresses::default();
5322 let mut table = match fde {
5323 Some(fde) => UnwindTable::new_for_fde(section, bases, &mut initial_ctx, &fde),
5324 None => UnwindTable::new_for_cie(section, bases, &mut initial_ctx, &cie),
5325 };
5326 for (expected_result, instruction) in instructions.as_ref() {
5327 assert_eq!(*expected_result, table.evaluate(instruction.clone()));
5328 }
5329 }
5330
5331 assert_eq!(expected_ctx, initial_ctx);
5332 }
5333
5334 fn make_test_cie<'a>() -> CommonInformationEntry<EndianSlice<'a, LittleEndian>> {
5335 CommonInformationEntry {
5336 offset: 0,
5337 format: Format::Dwarf64,
5338 length: 0,
5339 return_address_register: Register(0),
5340 version: 4,
5341 address_size: mem::size_of::<usize>() as u8,
5342 initial_instructions: EndianSlice::new(&[], LittleEndian),
5343 augmentation: None,
5344 data_alignment_factor: 2,
5345 code_alignment_factor: 3,
5346 }
5347 }
5348
5349 #[test]
5350 fn test_eval_set_loc() {
5351 let cie = make_test_cie();
5352 let ctx = UnwindContext::new();
5353 let mut expected = ctx.clone();
5354 expected.row_mut().end_address = 42;
5355 let instructions = [(Ok(true), CallFrameInstruction::SetLoc { address: 42 })];
5356 assert_eval(ctx, expected, cie, None, instructions);
5357 }
5358
5359 #[test]
5360 fn test_eval_set_loc_backwards() {
5361 let cie = make_test_cie();
5362 let mut ctx = UnwindContext::new();
5363 ctx.row_mut().start_address = 999;
5364 let expected = ctx.clone();
5365 let instructions = [(
5366 Err(Error::InvalidAddressRange),
5367 CallFrameInstruction::SetLoc { address: 42 },
5368 )];
5369 assert_eval(ctx, expected, cie, None, instructions);
5370 }
5371
5372 #[test]
5373 fn test_eval_advance_loc() {
5374 let cie = make_test_cie();
5375 let mut ctx = UnwindContext::new();
5376 ctx.row_mut().start_address = 3;
5377 let mut expected = ctx.clone();
5378 expected.row_mut().end_address = 3 + 2 * cie.code_alignment_factor;
5379 let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 2 })];
5380 assert_eval(ctx, expected, cie, None, instructions);
5381 }
5382
5383 #[test]
5384 fn test_eval_advance_loc_overflow_32() {
5385 let mut cie = make_test_cie();
5386 cie.address_size = 4;
5387 let mut ctx = UnwindContext::new();
5388 ctx.row_mut().start_address = u32::MAX.into();
5389 let expected = ctx.clone();
5390 let instructions = [(
5391 Err(Error::AddressOverflow),
5392 CallFrameInstruction::AdvanceLoc { delta: 42 },
5393 )];
5394 assert_eval(ctx, expected, cie, None, instructions);
5395 }
5396
5397 #[test]
5398 fn test_eval_advance_loc_overflow_64() {
5399 let mut cie = make_test_cie();
5400 cie.address_size = 8;
5401 let mut ctx = UnwindContext::new();
5402 ctx.row_mut().start_address = u64::MAX;
5403 let expected = ctx.clone();
5404 let instructions = [(
5405 Err(Error::AddressOverflow),
5406 CallFrameInstruction::AdvanceLoc { delta: 42 },
5407 )];
5408 assert_eval(ctx, expected, cie, None, instructions);
5409 }
5410
5411 #[test]
5412 fn test_eval_def_cfa() {
5413 let cie = make_test_cie();
5414 let ctx = UnwindContext::new();
5415 let mut expected = ctx.clone();
5416 expected.set_cfa(CfaRule::RegisterAndOffset {
5417 register: Register(42),
5418 offset: 36,
5419 });
5420 let instructions = [(
5421 Ok(false),
5422 CallFrameInstruction::DefCfa {
5423 register: Register(42),
5424 offset: 36,
5425 },
5426 )];
5427 assert_eval(ctx, expected, cie, None, instructions);
5428 }
5429
5430 #[test]
5431 fn test_eval_def_cfa_sf() {
5432 let cie = make_test_cie();
5433 let ctx = UnwindContext::new();
5434 let mut expected = ctx.clone();
5435 expected.set_cfa(CfaRule::RegisterAndOffset {
5436 register: Register(42),
5437 offset: 36 * cie.data_alignment_factor as i64,
5438 });
5439 let instructions = [(
5440 Ok(false),
5441 CallFrameInstruction::DefCfaSf {
5442 register: Register(42),
5443 factored_offset: 36,
5444 },
5445 )];
5446 assert_eval(ctx, expected, cie, None, instructions);
5447 }
5448
5449 #[test]
5450 fn test_eval_def_cfa_register() {
5451 let cie = make_test_cie();
5452 let mut ctx = UnwindContext::new();
5453 ctx.set_cfa(CfaRule::RegisterAndOffset {
5454 register: Register(3),
5455 offset: 8,
5456 });
5457 let mut expected = ctx.clone();
5458 expected.set_cfa(CfaRule::RegisterAndOffset {
5459 register: Register(42),
5460 offset: 8,
5461 });
5462 let instructions = [(
5463 Ok(false),
5464 CallFrameInstruction::DefCfaRegister {
5465 register: Register(42),
5466 },
5467 )];
5468 assert_eval(ctx, expected, cie, None, instructions);
5469 }
5470
5471 #[test]
5472 fn test_eval_def_cfa_register_invalid_context() {
5473 let cie = make_test_cie();
5474 let mut ctx = UnwindContext::new();
5475 ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5476 offset: 0,
5477 length: 0,
5478 }));
5479 let expected = ctx.clone();
5480 let instructions = [(
5481 Err(Error::CfiInstructionInInvalidContext),
5482 CallFrameInstruction::DefCfaRegister {
5483 register: Register(42),
5484 },
5485 )];
5486 assert_eval(ctx, expected, cie, None, instructions);
5487 }
5488
5489 #[test]
5490 fn test_eval_def_cfa_offset() {
5491 let cie = make_test_cie();
5492 let mut ctx = UnwindContext::new();
5493 ctx.set_cfa(CfaRule::RegisterAndOffset {
5494 register: Register(3),
5495 offset: 8,
5496 });
5497 let mut expected = ctx.clone();
5498 expected.set_cfa(CfaRule::RegisterAndOffset {
5499 register: Register(3),
5500 offset: 42,
5501 });
5502 let instructions = [(Ok(false), CallFrameInstruction::DefCfaOffset { offset: 42 })];
5503 assert_eval(ctx, expected, cie, None, instructions);
5504 }
5505
5506 #[test]
5507 fn test_eval_def_cfa_offset_invalid_context() {
5508 let cie = make_test_cie();
5509 let mut ctx = UnwindContext::new();
5510 ctx.set_cfa(CfaRule::Expression(UnwindExpression {
5511 offset: 10,
5512 length: 11,
5513 }));
5514 let expected = ctx.clone();
5515 let instructions = [(
5516 Err(Error::CfiInstructionInInvalidContext),
5517 CallFrameInstruction::DefCfaOffset { offset: 1993 },
5518 )];
5519 assert_eval(ctx, expected, cie, None, instructions);
5520 }
5521
5522 #[test]
5523 fn test_eval_def_cfa_expression() {
5524 let expr = UnwindExpression {
5525 offset: 10,
5526 length: 11,
5527 };
5528 let cie = make_test_cie();
5529 let ctx = UnwindContext::new();
5530 let mut expected = ctx.clone();
5531 expected.set_cfa(CfaRule::Expression(expr));
5532 let instructions = [(
5533 Ok(false),
5534 CallFrameInstruction::DefCfaExpression { expression: expr },
5535 )];
5536 assert_eval(ctx, expected, cie, None, instructions);
5537 }
5538
5539 #[test]
5540 fn test_eval_undefined() {
5541 let cie = make_test_cie();
5542 let ctx = UnwindContext::new();
5543 let mut expected = ctx.clone();
5544 expected
5545 .set_register_rule(Register(5), RegisterRule::Undefined)
5546 .unwrap();
5547 let instructions = [(
5548 Ok(false),
5549 CallFrameInstruction::Undefined {
5550 register: Register(5),
5551 },
5552 )];
5553 assert_eval(ctx, expected, cie, None, instructions);
5554 }
5555
5556 #[test]
5557 fn test_eval_same_value() {
5558 let cie = make_test_cie();
5559 let ctx = UnwindContext::new();
5560 let mut expected = ctx.clone();
5561 expected
5562 .set_register_rule(Register(0), RegisterRule::SameValue)
5563 .unwrap();
5564 let instructions = [(
5565 Ok(false),
5566 CallFrameInstruction::SameValue {
5567 register: Register(0),
5568 },
5569 )];
5570 assert_eval(ctx, expected, cie, None, instructions);
5571 }
5572
5573 #[test]
5574 fn test_eval_offset() {
5575 let cie = make_test_cie();
5576 let ctx = UnwindContext::new();
5577 let mut expected = ctx.clone();
5578 expected
5579 .set_register_rule(
5580 Register(2),
5581 RegisterRule::Offset(3 * cie.data_alignment_factor),
5582 )
5583 .unwrap();
5584 let instructions = [(
5585 Ok(false),
5586 CallFrameInstruction::Offset {
5587 register: Register(2),
5588 factored_offset: 3,
5589 },
5590 )];
5591 assert_eval(ctx, expected, cie, None, instructions);
5592 }
5593
5594 #[test]
5595 fn test_eval_offset_extended_sf() {
5596 let cie = make_test_cie();
5597 let ctx = UnwindContext::new();
5598 let mut expected = ctx.clone();
5599 expected
5600 .set_register_rule(
5601 Register(4),
5602 RegisterRule::Offset(-3 * cie.data_alignment_factor),
5603 )
5604 .unwrap();
5605 let instructions = [(
5606 Ok(false),
5607 CallFrameInstruction::OffsetExtendedSf {
5608 register: Register(4),
5609 factored_offset: -3,
5610 },
5611 )];
5612 assert_eval(ctx, expected, cie, None, instructions);
5613 }
5614
5615 #[test]
5616 fn test_eval_val_offset() {
5617 let cie = make_test_cie();
5618 let ctx = UnwindContext::new();
5619 let mut expected = ctx.clone();
5620 expected
5621 .set_register_rule(
5622 Register(5),
5623 RegisterRule::ValOffset(7 * cie.data_alignment_factor),
5624 )
5625 .unwrap();
5626 let instructions = [(
5627 Ok(false),
5628 CallFrameInstruction::ValOffset {
5629 register: Register(5),
5630 factored_offset: 7,
5631 },
5632 )];
5633 assert_eval(ctx, expected, cie, None, instructions);
5634 }
5635
5636 #[test]
5637 fn test_eval_val_offset_sf() {
5638 let cie = make_test_cie();
5639 let ctx = UnwindContext::new();
5640 let mut expected = ctx.clone();
5641 expected
5642 .set_register_rule(
5643 Register(5),
5644 RegisterRule::ValOffset(-7 * cie.data_alignment_factor),
5645 )
5646 .unwrap();
5647 let instructions = [(
5648 Ok(false),
5649 CallFrameInstruction::ValOffsetSf {
5650 register: Register(5),
5651 factored_offset: -7,
5652 },
5653 )];
5654 assert_eval(ctx, expected, cie, None, instructions);
5655 }
5656
5657 #[test]
5658 fn test_eval_expression() {
5659 let expr = UnwindExpression {
5660 offset: 10,
5661 length: 11,
5662 };
5663 let cie = make_test_cie();
5664 let ctx = UnwindContext::new();
5665 let mut expected = ctx.clone();
5666 expected
5667 .set_register_rule(Register(9), RegisterRule::Expression(expr))
5668 .unwrap();
5669 let instructions = [(
5670 Ok(false),
5671 CallFrameInstruction::Expression {
5672 register: Register(9),
5673 expression: expr,
5674 },
5675 )];
5676 assert_eval(ctx, expected, cie, None, instructions);
5677 }
5678
5679 #[test]
5680 fn test_eval_val_expression() {
5681 let expr = UnwindExpression {
5682 offset: 10,
5683 length: 11,
5684 };
5685 let cie = make_test_cie();
5686 let ctx = UnwindContext::new();
5687 let mut expected = ctx.clone();
5688 expected
5689 .set_register_rule(Register(9), RegisterRule::ValExpression(expr))
5690 .unwrap();
5691 let instructions = [(
5692 Ok(false),
5693 CallFrameInstruction::ValExpression {
5694 register: Register(9),
5695 expression: expr,
5696 },
5697 )];
5698 assert_eval(ctx, expected, cie, None, instructions);
5699 }
5700
5701 #[test]
5702 fn test_eval_restore() {
5703 let cie = make_test_cie();
5704 let fde = FrameDescriptionEntry {
5705 offset: 0,
5706 format: Format::Dwarf64,
5707 length: 0,
5708 address_range: 0,
5709 augmentation: None,
5710 initial_address: 0,
5711 cie: cie.clone(),
5712 instructions: EndianSlice::new(&[], LittleEndian),
5713 };
5714
5715 let mut ctx = UnwindContext::new();
5716 ctx.set_register_rule(Register(0), RegisterRule::Offset(1))
5717 .unwrap();
5718 ctx.save_initial_rules().unwrap();
5719 let expected = ctx.clone();
5720 ctx.set_register_rule(Register(0), RegisterRule::Offset(2))
5721 .unwrap();
5722
5723 let instructions = [(
5724 Ok(false),
5725 CallFrameInstruction::Restore {
5726 register: Register(0),
5727 },
5728 )];
5729 assert_eval(ctx, expected, cie, Some(fde), instructions);
5730 }
5731
5732 #[test]
5733 fn test_eval_restore_havent_saved_initial_context() {
5734 let cie = make_test_cie();
5735 let ctx = UnwindContext::new();
5736 let expected = ctx.clone();
5737 let instructions = [(
5738 Err(Error::CfiInstructionInInvalidContext),
5739 CallFrameInstruction::Restore {
5740 register: Register(0),
5741 },
5742 )];
5743 assert_eval(ctx, expected, cie, None, instructions);
5744 }
5745
5746 #[test]
5747 fn test_eval_remember_state() {
5748 let cie = make_test_cie();
5749 let ctx = UnwindContext::new();
5750 let mut expected = ctx.clone();
5751 expected.push_row().unwrap();
5752 let instructions = [(Ok(false), CallFrameInstruction::RememberState)];
5753 assert_eval(ctx, expected, cie, None, instructions);
5754 }
5755
5756 #[test]
5757 fn test_eval_restore_state() {
5758 let cie = make_test_cie();
5759
5760 let mut ctx = UnwindContext::new();
5761 ctx.set_start_address(1);
5762 ctx.set_register_rule(Register(0), RegisterRule::SameValue)
5763 .unwrap();
5764 let mut expected = ctx.clone();
5765 ctx.push_row().unwrap();
5766 ctx.set_start_address(2);
5767 ctx.set_register_rule(Register(0), RegisterRule::Offset(16))
5768 .unwrap();
5769
5770 expected.set_start_address(2);
5772
5773 let instructions = [
5774 (Ok(false), CallFrameInstruction::RestoreState),
5776 (
5778 Err(Error::PopWithEmptyStack),
5779 CallFrameInstruction::RestoreState,
5780 ),
5781 ];
5782
5783 assert_eval(ctx, expected, cie, None, instructions);
5784 }
5785
5786 #[test]
5787 fn test_eval_negate_ra_state() {
5788 let cie = make_test_cie();
5789 let ctx = UnwindContext::new();
5790 let mut expected = ctx.clone();
5791 expected
5792 .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(1))
5793 .unwrap();
5794 let instructions = [(Ok(false), CallFrameInstruction::NegateRaState)];
5795 assert_eval(ctx, expected, cie, None, instructions);
5796
5797 let cie = make_test_cie();
5798 let ctx = UnwindContext::new();
5799 let mut expected = ctx.clone();
5800 expected
5801 .set_register_rule(crate::AArch64::RA_SIGN_STATE, RegisterRule::Constant(0))
5802 .unwrap();
5803 let instructions = [
5804 (Ok(false), CallFrameInstruction::NegateRaState),
5805 (Ok(false), CallFrameInstruction::NegateRaState),
5806 ];
5807 assert_eval(ctx, expected, cie, None, instructions);
5808
5809 let cie = make_test_cie();
5811 let ctx = UnwindContext::new();
5812 let mut expected = ctx.clone();
5813 expected
5814 .set_register_rule(
5815 crate::AArch64::RA_SIGN_STATE,
5816 RegisterRule::Offset(cie.data_alignment_factor as i64),
5817 )
5818 .unwrap();
5819 let instructions = [
5820 (
5821 Ok(false),
5822 CallFrameInstruction::Offset {
5823 register: crate::AArch64::RA_SIGN_STATE,
5824 factored_offset: 1,
5825 },
5826 ),
5827 (
5828 Err(Error::CfiInstructionInInvalidContext),
5829 CallFrameInstruction::NegateRaState,
5830 ),
5831 ];
5832 assert_eval(ctx, expected, cie, None, instructions);
5833 }
5834
5835 #[test]
5836 fn test_eval_nop() {
5837 let cie = make_test_cie();
5838 let ctx = UnwindContext::new();
5839 let expected = ctx.clone();
5840 let instructions = [(Ok(false), CallFrameInstruction::Nop)];
5841 assert_eval(ctx, expected, cie, None, instructions);
5842 }
5843
5844 #[test]
5845 fn test_unwind_table_cie_no_rule() {
5846 let initial_instructions = Section::with_endian(Endian::Little)
5847 .D8(constants::DW_CFA_def_cfa_sf.0)
5849 .uleb(4)
5850 .sleb(-12)
5851 .append_repeated(constants::DW_CFA_nop.0, 4);
5852 let initial_instructions = initial_instructions.get_contents().unwrap();
5853
5854 let cie = CommonInformationEntry {
5855 offset: 0,
5856 length: 0,
5857 format: Format::Dwarf32,
5858 version: 4,
5859 augmentation: None,
5860 address_size: 8,
5861 code_alignment_factor: 1,
5862 data_alignment_factor: 1,
5863 return_address_register: Register(3),
5864 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5865 };
5866
5867 let instructions = Section::with_endian(Endian::Little)
5868 .append_repeated(constants::DW_CFA_nop.0, 8);
5870 let instructions = instructions.get_contents().unwrap();
5871
5872 let fde = FrameDescriptionEntry {
5873 offset: 0,
5874 length: 0,
5875 format: Format::Dwarf32,
5876 cie: cie.clone(),
5877 initial_address: 0,
5878 address_range: 100,
5879 augmentation: None,
5880 instructions: EndianSlice::new(&instructions, LittleEndian),
5881 };
5882
5883 let section = &DebugFrame::from(EndianSlice::default());
5884 let bases = &BaseAddresses::default();
5885 let mut ctx = Box::new(UnwindContext::new());
5886
5887 let mut table = fde
5888 .rows(section, bases, &mut ctx)
5889 .expect("Should run initial program OK");
5890 assert!(table.ctx.is_initialized);
5891 let expected_initial_rule = (Register(0), RegisterRule::Undefined);
5892 assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5893
5894 {
5895 let row = table.next_row().expect("Should evaluate first row OK");
5896 let expected = UnwindTableRow {
5897 start_address: 0,
5898 end_address: 100,
5899 saved_args_size: 0,
5900 cfa: CfaRule::RegisterAndOffset {
5901 register: Register(4),
5902 offset: -12,
5903 },
5904 registers: [].iter().collect(),
5905 };
5906 assert_eq!(Some(&expected), row);
5907 }
5908
5909 assert_eq!(Ok(None), table.next_row());
5911 assert_eq!(Ok(None), table.next_row());
5912 }
5913
5914 #[test]
5915 fn test_unwind_table_cie_single_rule() {
5916 let initial_instructions = Section::with_endian(Endian::Little)
5917 .D8(constants::DW_CFA_def_cfa_sf.0)
5919 .uleb(4)
5920 .sleb(-12)
5921 .D8(constants::DW_CFA_offset.0 | 3)
5923 .uleb(4)
5924 .append_repeated(constants::DW_CFA_nop.0, 4);
5925 let initial_instructions = initial_instructions.get_contents().unwrap();
5926
5927 let cie = CommonInformationEntry {
5928 offset: 0,
5929 length: 0,
5930 format: Format::Dwarf32,
5931 version: 4,
5932 augmentation: None,
5933 address_size: 8,
5934 code_alignment_factor: 1,
5935 data_alignment_factor: 1,
5936 return_address_register: Register(3),
5937 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
5938 };
5939
5940 let instructions = Section::with_endian(Endian::Little)
5941 .append_repeated(constants::DW_CFA_nop.0, 8);
5943 let instructions = instructions.get_contents().unwrap();
5944
5945 let fde = FrameDescriptionEntry {
5946 offset: 0,
5947 length: 0,
5948 format: Format::Dwarf32,
5949 cie: cie.clone(),
5950 initial_address: 0,
5951 address_range: 100,
5952 augmentation: None,
5953 instructions: EndianSlice::new(&instructions, LittleEndian),
5954 };
5955
5956 let section = &DebugFrame::from(EndianSlice::default());
5957 let bases = &BaseAddresses::default();
5958 let mut ctx = Box::new(UnwindContext::new());
5959
5960 let mut table = fde
5961 .rows(section, bases, &mut ctx)
5962 .expect("Should run initial program OK");
5963 assert!(table.ctx.is_initialized);
5964 let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
5965 assert_eq!(table.ctx.initial_rule, Some(expected_initial_rule));
5966
5967 {
5968 let row = table.next_row().expect("Should evaluate first row OK");
5969 let expected = UnwindTableRow {
5970 start_address: 0,
5971 end_address: 100,
5972 saved_args_size: 0,
5973 cfa: CfaRule::RegisterAndOffset {
5974 register: Register(4),
5975 offset: -12,
5976 },
5977 registers: [(Register(3), RegisterRule::Offset(4))].iter().collect(),
5978 };
5979 assert_eq!(Some(&expected), row);
5980 }
5981
5982 assert_eq!(Ok(None), table.next_row());
5984 assert_eq!(Ok(None), table.next_row());
5985 }
5986
5987 #[test]
5988 fn test_unwind_table_cie_invalid_rule() {
5989 let initial_instructions1 = Section::with_endian(Endian::Little)
5990 .D8(constants::DW_CFA_remember_state.0)
5992 .D8(constants::DW_CFA_offset.0 | 4)
5994 .uleb(8)
5995 .D8(constants::DW_CFA_offset.0);
5997 let initial_instructions1 = initial_instructions1.get_contents().unwrap();
5998
5999 let cie1 = CommonInformationEntry {
6000 offset: 0,
6001 length: 0,
6002 format: Format::Dwarf32,
6003 version: 4,
6004 augmentation: None,
6005 address_size: 8,
6006 code_alignment_factor: 1,
6007 data_alignment_factor: 1,
6008 return_address_register: Register(3),
6009 initial_instructions: EndianSlice::new(&initial_instructions1, LittleEndian),
6010 };
6011
6012 let initial_instructions2 = Section::with_endian(Endian::Little)
6013 .D8(constants::DW_CFA_offset.0 | 3)
6015 .uleb(4)
6016 .append_repeated(constants::DW_CFA_nop.0, 4);
6017 let initial_instructions2 = initial_instructions2.get_contents().unwrap();
6018
6019 let cie2 = CommonInformationEntry {
6020 offset: 0,
6021 length: 0,
6022 format: Format::Dwarf32,
6023 version: 4,
6024 augmentation: None,
6025 address_size: 8,
6026 code_alignment_factor: 1,
6027 data_alignment_factor: 1,
6028 return_address_register: Register(3),
6029 initial_instructions: EndianSlice::new(&initial_instructions2, LittleEndian),
6030 };
6031
6032 let fde1 = FrameDescriptionEntry {
6033 offset: 0,
6034 length: 0,
6035 format: Format::Dwarf32,
6036 cie: cie1.clone(),
6037 initial_address: 0,
6038 address_range: 100,
6039 augmentation: None,
6040 instructions: EndianSlice::new(&[], LittleEndian),
6041 };
6042
6043 let fde2 = FrameDescriptionEntry {
6044 offset: 0,
6045 length: 0,
6046 format: Format::Dwarf32,
6047 cie: cie2.clone(),
6048 initial_address: 0,
6049 address_range: 100,
6050 augmentation: None,
6051 instructions: EndianSlice::new(&[], LittleEndian),
6052 };
6053
6054 let section = &DebugFrame::from(EndianSlice::default());
6055 let bases = &BaseAddresses::default();
6056 let mut ctx = Box::new(UnwindContext::new());
6057
6058 let table = fde1
6059 .rows(section, bases, &mut ctx)
6060 .map_eof(&initial_instructions1);
6061 assert_eq!(table.err(), Some(Error::UnexpectedEof(ReaderOffsetId(4))));
6062 assert!(!ctx.is_initialized);
6063 assert_eq!(ctx.stack.len(), 2);
6064 assert_eq!(ctx.initial_rule, None);
6065
6066 let _table = fde2
6067 .rows(section, bases, &mut ctx)
6068 .expect("Should run initial program OK");
6069 assert!(ctx.is_initialized);
6070 assert_eq!(ctx.stack.len(), 1);
6071 let expected_initial_rule = (Register(3), RegisterRule::Offset(4));
6072 assert_eq!(ctx.initial_rule, Some(expected_initial_rule));
6073 }
6074
6075 #[test]
6076 fn test_unwind_table_next_row() {
6077 #[allow(clippy::identity_op)]
6078 let initial_instructions = Section::with_endian(Endian::Little)
6079 .D8(constants::DW_CFA_def_cfa_sf.0)
6081 .uleb(4)
6082 .sleb(-12)
6083 .D8(constants::DW_CFA_offset.0 | 0)
6085 .uleb(8)
6086 .D8(constants::DW_CFA_offset.0 | 3)
6088 .uleb(4)
6089 .append_repeated(constants::DW_CFA_nop.0, 4);
6090 let initial_instructions = initial_instructions.get_contents().unwrap();
6091
6092 let cie = CommonInformationEntry {
6093 offset: 0,
6094 length: 0,
6095 format: Format::Dwarf32,
6096 version: 4,
6097 augmentation: None,
6098 address_size: 8,
6099 code_alignment_factor: 1,
6100 data_alignment_factor: 1,
6101 return_address_register: Register(3),
6102 initial_instructions: EndianSlice::new(&initial_instructions, LittleEndian),
6103 };
6104
6105 let instructions = Section::with_endian(Endian::Little)
6106 .D8(constants::DW_CFA_advance_loc1.0)
6108 .D8(1)
6109 .D8(constants::DW_CFA_offset_extended_sf.0)
6111 .uleb(0)
6112 .sleb(-16)
6113 .D8(constants::DW_CFA_advance_loc1.0)
6115 .D8(32)
6116 .D8(constants::DW_CFA_offset_extended_sf.0)
6118 .uleb(3)
6119 .sleb(-4)
6120 .D8(constants::DW_CFA_advance_loc1.0)
6122 .D8(64)
6123 .D8(constants::DW_CFA_offset.0 | 5)
6125 .uleb(4)
6126 .append_repeated(constants::DW_CFA_nop.0, 8);
6128 let instructions = instructions.get_contents().unwrap();
6129
6130 let fde = FrameDescriptionEntry {
6131 offset: 0,
6132 length: 0,
6133 format: Format::Dwarf32,
6134 cie: cie.clone(),
6135 initial_address: 0,
6136 address_range: 100,
6137 augmentation: None,
6138 instructions: EndianSlice::new(&instructions, LittleEndian),
6139 };
6140
6141 let section = &DebugFrame::from(EndianSlice::default());
6142 let bases = &BaseAddresses::default();
6143 let mut ctx = Box::new(UnwindContext::new());
6144
6145 let mut table = fde
6146 .rows(section, bases, &mut ctx)
6147 .expect("Should run initial program OK");
6148 assert!(table.ctx.is_initialized);
6149 assert!(table.ctx.initial_rule.is_none());
6150 let expected_initial_rules: RegisterRuleMap<_> = [
6151 (Register(0), RegisterRule::Offset(8)),
6152 (Register(3), RegisterRule::Offset(4)),
6153 ]
6154 .iter()
6155 .collect();
6156 assert_eq!(table.ctx.stack[0].registers, expected_initial_rules);
6157
6158 {
6159 let row = table.next_row().expect("Should evaluate first row OK");
6160 let expected = UnwindTableRow {
6161 start_address: 0,
6162 end_address: 1,
6163 saved_args_size: 0,
6164 cfa: CfaRule::RegisterAndOffset {
6165 register: Register(4),
6166 offset: -12,
6167 },
6168 registers: [
6169 (Register(0), RegisterRule::Offset(8)),
6170 (Register(3), RegisterRule::Offset(4)),
6171 ]
6172 .iter()
6173 .collect(),
6174 };
6175 assert_eq!(Some(&expected), row);
6176 }
6177
6178 {
6179 let row = table.next_row().expect("Should evaluate second row OK");
6180 let expected = UnwindTableRow {
6181 start_address: 1,
6182 end_address: 33,
6183 saved_args_size: 0,
6184 cfa: CfaRule::RegisterAndOffset {
6185 register: Register(4),
6186 offset: -12,
6187 },
6188 registers: [
6189 (Register(0), RegisterRule::Offset(-16)),
6190 (Register(3), RegisterRule::Offset(4)),
6191 ]
6192 .iter()
6193 .collect(),
6194 };
6195 assert_eq!(Some(&expected), row);
6196 }
6197
6198 {
6199 let row = table.next_row().expect("Should evaluate third row OK");
6200 let expected = UnwindTableRow {
6201 start_address: 33,
6202 end_address: 97,
6203 saved_args_size: 0,
6204 cfa: CfaRule::RegisterAndOffset {
6205 register: Register(4),
6206 offset: -12,
6207 },
6208 registers: [
6209 (Register(0), RegisterRule::Offset(-16)),
6210 (Register(3), RegisterRule::Offset(-4)),
6211 ]
6212 .iter()
6213 .collect(),
6214 };
6215 assert_eq!(Some(&expected), row);
6216 }
6217
6218 {
6219 let row = table.next_row().expect("Should evaluate fourth row OK");
6220 let expected = UnwindTableRow {
6221 start_address: 97,
6222 end_address: 100,
6223 saved_args_size: 0,
6224 cfa: CfaRule::RegisterAndOffset {
6225 register: Register(4),
6226 offset: -12,
6227 },
6228 registers: [
6229 (Register(0), RegisterRule::Offset(-16)),
6230 (Register(3), RegisterRule::Offset(-4)),
6231 (Register(5), RegisterRule::Offset(4)),
6232 ]
6233 .iter()
6234 .collect(),
6235 };
6236 assert_eq!(Some(&expected), row);
6237 }
6238
6239 assert_eq!(Ok(None), table.next_row());
6241 assert_eq!(Ok(None), table.next_row());
6242 }
6243
6244 #[test]
6245 fn test_unwind_info_for_address_ok() {
6246 let instrs1 = Section::with_endian(Endian::Big)
6247 .D8(constants::DW_CFA_def_cfa_sf.0)
6249 .uleb(4)
6250 .sleb(-12);
6251 let instrs1 = instrs1.get_contents().unwrap();
6252
6253 let instrs2: Vec<_> = (0..8).map(|_| constants::DW_CFA_nop.0).collect();
6254
6255 let instrs3 = Section::with_endian(Endian::Big)
6256 .D8(constants::DW_CFA_advance_loc1.0)
6258 .D8(100)
6259 .D8(constants::DW_CFA_offset_extended_sf.0)
6261 .uleb(0)
6262 .sleb(-16);
6263 let instrs3 = instrs3.get_contents().unwrap();
6264
6265 let instrs4: Vec<_> = (0..16).map(|_| constants::DW_CFA_nop.0).collect();
6266
6267 let mut cie1 = CommonInformationEntry {
6268 offset: 0,
6269 length: 0,
6270 format: Format::Dwarf32,
6271 version: 4,
6272 augmentation: None,
6273 address_size: 8,
6274 code_alignment_factor: 1,
6275 data_alignment_factor: 1,
6276 return_address_register: Register(3),
6277 initial_instructions: EndianSlice::new(&instrs1, BigEndian),
6278 };
6279
6280 let mut cie2 = CommonInformationEntry {
6281 offset: 0,
6282 length: 0,
6283 format: Format::Dwarf32,
6284 version: 4,
6285 augmentation: None,
6286 address_size: 4,
6287 code_alignment_factor: 1,
6288 data_alignment_factor: 1,
6289 return_address_register: Register(1),
6290 initial_instructions: EndianSlice::new(&instrs2, BigEndian),
6291 };
6292
6293 let cie1_location = Label::new();
6294 let cie2_location = Label::new();
6295
6296 let kind = debug_frame_be();
6300 let section = Section::with_endian(kind.endian())
6301 .mark(&cie1_location)
6302 .cie(kind, None, &mut cie1)
6303 .mark(&cie2_location)
6304 .cie(kind, None, &mut cie2);
6305
6306 let mut fde1 = FrameDescriptionEntry {
6307 offset: 0,
6308 length: 0,
6309 format: Format::Dwarf32,
6310 cie: cie1.clone(),
6311 initial_address: 0xfeed_beef,
6312 address_range: 200,
6313 augmentation: None,
6314 instructions: EndianSlice::new(&instrs3, BigEndian),
6315 };
6316
6317 let mut fde2 = FrameDescriptionEntry {
6318 offset: 0,
6319 length: 0,
6320 format: Format::Dwarf32,
6321 cie: cie2.clone(),
6322 initial_address: 0xfeed_face,
6323 address_range: 9000,
6324 augmentation: None,
6325 instructions: EndianSlice::new(&instrs4, BigEndian),
6326 };
6327
6328 let section =
6329 section
6330 .fde(kind, &cie1_location, &mut fde1)
6331 .fde(kind, &cie2_location, &mut fde2);
6332 section.start().set_const(0);
6333
6334 let contents = section.get_contents().unwrap();
6335 let debug_frame = kind.section(&contents);
6336
6337 let bases = Default::default();
6339 let mut ctx = Box::new(UnwindContext::new());
6340 let result = debug_frame.unwind_info_for_address(
6341 &bases,
6342 &mut ctx,
6343 0xfeed_beef + 150,
6344 DebugFrame::cie_from_offset,
6345 );
6346 assert!(result.is_ok());
6347 let unwind_info = result.unwrap();
6348
6349 assert_eq!(
6350 *unwind_info,
6351 UnwindTableRow {
6352 start_address: fde1.initial_address() + 100,
6353 end_address: fde1.end_address(),
6354 saved_args_size: 0,
6355 cfa: CfaRule::RegisterAndOffset {
6356 register: Register(4),
6357 offset: -12,
6358 },
6359 registers: [(Register(0), RegisterRule::Offset(-16))].iter().collect(),
6360 }
6361 );
6362 }
6363
6364 #[test]
6365 fn test_unwind_info_for_address_not_found() {
6366 let debug_frame = DebugFrame::new(&[], NativeEndian);
6367 let bases = Default::default();
6368 let mut ctx = Box::new(UnwindContext::new());
6369 let result = debug_frame.unwind_info_for_address(
6370 &bases,
6371 &mut ctx,
6372 0xbadb_ad99,
6373 DebugFrame::cie_from_offset,
6374 );
6375 assert!(result.is_err());
6376 assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
6377 }
6378
6379 #[test]
6380 fn test_eh_frame_hdr_unknown_version() {
6381 let bases = BaseAddresses::default();
6382 let buf = &[42];
6383 let result = EhFrameHdr::new(buf, NativeEndian).parse(&bases, 8);
6384 assert!(result.is_err());
6385 assert_eq!(result.unwrap_err(), Error::UnknownVersion(42));
6386 }
6387
6388 #[test]
6389 fn test_eh_frame_hdr_omit_ehptr() {
6390 let section = Section::with_endian(Endian::Little)
6391 .L8(1)
6392 .L8(0xff)
6393 .L8(0x03)
6394 .L8(0x0b)
6395 .L32(2)
6396 .L32(10)
6397 .L32(1)
6398 .L32(20)
6399 .L32(2)
6400 .L32(0);
6401 let section = section.get_contents().unwrap();
6402 let bases = BaseAddresses::default();
6403 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6404 assert!(result.is_err());
6405 assert_eq!(result.unwrap_err(), Error::CannotParseOmitPointerEncoding);
6406 }
6407
6408 #[test]
6409 fn test_eh_frame_hdr_omit_count() {
6410 let section = Section::with_endian(Endian::Little)
6411 .L8(1)
6412 .L8(0x0b)
6413 .L8(0xff)
6414 .L8(0x0b)
6415 .L32(0x12345);
6416 let section = section.get_contents().unwrap();
6417 let bases = BaseAddresses::default();
6418 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6419 assert!(result.is_ok());
6420 let result = result.unwrap();
6421 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6422 assert!(result.table().is_none());
6423 }
6424
6425 #[test]
6426 fn test_eh_frame_hdr_omit_table() {
6427 let section = Section::with_endian(Endian::Little)
6428 .L8(1)
6429 .L8(0x0b)
6430 .L8(0x03)
6431 .L8(0xff)
6432 .L32(0x12345)
6433 .L32(2);
6434 let section = section.get_contents().unwrap();
6435 let bases = BaseAddresses::default();
6436 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6437 assert!(result.is_ok());
6438 let result = result.unwrap();
6439 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6440 assert!(result.table().is_none());
6441 }
6442
6443 #[test]
6444 fn test_eh_frame_hdr_varlen_table() {
6445 let section = Section::with_endian(Endian::Little)
6446 .L8(1)
6447 .L8(0x0b)
6448 .L8(0x03)
6449 .L8(0x01)
6450 .L32(0x12345)
6451 .L32(2);
6452 let section = section.get_contents().unwrap();
6453 let bases = BaseAddresses::default();
6454 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6455 assert!(result.is_ok());
6456 let result = result.unwrap();
6457 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6458 let table = result.table();
6459 assert!(table.is_some());
6460 let table = table.unwrap();
6461 assert_eq!(
6462 table.lookup(0, &bases),
6463 Err(Error::VariableLengthSearchTable)
6464 );
6465 }
6466
6467 #[test]
6468 fn test_eh_frame_hdr_indirect_length() {
6469 let section = Section::with_endian(Endian::Little)
6470 .L8(1)
6471 .L8(0x0b)
6472 .L8(0x83)
6473 .L8(0x0b)
6474 .L32(0x12345)
6475 .L32(2);
6476 let section = section.get_contents().unwrap();
6477 let bases = BaseAddresses::default();
6478 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6479 assert!(result.is_err());
6480 assert_eq!(result.unwrap_err(), Error::UnsupportedPointerEncoding);
6481 }
6482
6483 #[test]
6484 fn test_eh_frame_hdr_indirect_ptrs() {
6485 let section = Section::with_endian(Endian::Little)
6486 .L8(1)
6487 .L8(0x8b)
6488 .L8(0x03)
6489 .L8(0x8b)
6490 .L32(0x12345)
6491 .L32(2)
6492 .L32(10)
6493 .L32(1)
6494 .L32(20)
6495 .L32(2);
6496 let section = section.get_contents().unwrap();
6497 let bases = BaseAddresses::default();
6498 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6499 assert!(result.is_ok());
6500 let result = result.unwrap();
6501 assert_eq!(result.eh_frame_ptr(), Pointer::Indirect(0x12345));
6502 let table = result.table();
6503 assert!(table.is_some());
6504 let table = table.unwrap();
6505 assert_eq!(
6506 table.lookup(0, &bases),
6507 Err(Error::UnsupportedPointerEncoding)
6508 );
6509 }
6510
6511 #[test]
6512 fn test_eh_frame_hdr_good() {
6513 let section = Section::with_endian(Endian::Little)
6514 .L8(1)
6515 .L8(0x0b)
6516 .L8(0x03)
6517 .L8(0x0b)
6518 .L32(0x12345)
6519 .L32(2)
6520 .L32(10)
6521 .L32(1)
6522 .L32(20)
6523 .L32(2);
6524 let section = section.get_contents().unwrap();
6525 let bases = BaseAddresses::default();
6526 let result = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6527 assert!(result.is_ok());
6528 let result = result.unwrap();
6529 assert_eq!(result.eh_frame_ptr(), Pointer::Direct(0x12345));
6530 let table = result.table();
6531 assert!(table.is_some());
6532 let table = table.unwrap();
6533 assert_eq!(table.lookup(0, &bases), Ok(Pointer::Direct(1)));
6534 assert_eq!(table.lookup(9, &bases), Ok(Pointer::Direct(1)));
6535 assert_eq!(table.lookup(10, &bases), Ok(Pointer::Direct(1)));
6536 assert_eq!(table.lookup(11, &bases), Ok(Pointer::Direct(1)));
6537 assert_eq!(table.lookup(19, &bases), Ok(Pointer::Direct(1)));
6538 assert_eq!(table.lookup(20, &bases), Ok(Pointer::Direct(2)));
6539 assert_eq!(table.lookup(21, &bases), Ok(Pointer::Direct(2)));
6540 assert_eq!(table.lookup(100_000, &bases), Ok(Pointer::Direct(2)));
6541 }
6542
6543 #[test]
6544 fn test_eh_frame_fde_for_address_good() {
6545 let mut cie = make_test_cie();
6549 cie.format = Format::Dwarf32;
6550 cie.version = 1;
6551
6552 let start_of_cie = Label::new();
6553 let end_of_cie = Label::new();
6554
6555 let kind = eh_frame_le();
6556 let section = Section::with_endian(kind.endian())
6557 .append_repeated(0, 16)
6558 .mark(&start_of_cie)
6559 .cie(kind, None, &mut cie)
6560 .mark(&end_of_cie);
6561
6562 let mut fde1 = FrameDescriptionEntry {
6563 offset: 0,
6564 length: 0,
6565 format: Format::Dwarf32,
6566 cie: cie.clone(),
6567 initial_address: 9,
6568 address_range: 4,
6569 augmentation: None,
6570 instructions: EndianSlice::new(&[], LittleEndian),
6571 };
6572 let mut fde2 = FrameDescriptionEntry {
6573 offset: 0,
6574 length: 0,
6575 format: Format::Dwarf32,
6576 cie: cie.clone(),
6577 initial_address: 20,
6578 address_range: 8,
6579 augmentation: None,
6580 instructions: EndianSlice::new(&[], LittleEndian),
6581 };
6582
6583 let start_of_fde1 = Label::new();
6584 let start_of_fde2 = Label::new();
6585
6586 let section = section
6587 .mark(&start_of_fde1)
6589 .fde(kind, (&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1)
6590 .mark(&start_of_fde2)
6591 .fde(kind, (&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2);
6592
6593 section.start().set_const(0);
6594 let section = section.get_contents().unwrap();
6595 let eh_frame = kind.section(§ion);
6596
6597 let section = Section::with_endian(kind.endian())
6599 .L8(1)
6600 .L8(0x0b)
6601 .L8(0x03)
6602 .L8(0x0b)
6603 .L32(0x12345)
6604 .L32(2)
6605 .L32(10)
6606 .L32(0x12345 + start_of_fde1.value().unwrap() as u32)
6607 .L32(20)
6608 .L32(0x12345 + start_of_fde2.value().unwrap() as u32);
6609
6610 let section = section.get_contents().unwrap();
6611 let bases = BaseAddresses::default();
6612 let eh_frame_hdr = EhFrameHdr::new(§ion, LittleEndian).parse(&bases, 8);
6613 assert!(eh_frame_hdr.is_ok());
6614 let eh_frame_hdr = eh_frame_hdr.unwrap();
6615
6616 let table = eh_frame_hdr.table();
6617 assert!(table.is_some());
6618 let table = table.unwrap();
6619
6620 let bases = Default::default();
6621 let mut iter = table.iter(&bases);
6622 assert_eq!(
6623 iter.next(),
6624 Ok(Some((
6625 Pointer::Direct(10),
6626 Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6627 )))
6628 );
6629 assert_eq!(
6630 iter.next(),
6631 Ok(Some((
6632 Pointer::Direct(20),
6633 Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6634 )))
6635 );
6636 assert_eq!(iter.next(), Ok(None));
6637
6638 assert_eq!(
6639 table.iter(&bases).nth(0),
6640 Ok(Some((
6641 Pointer::Direct(10),
6642 Pointer::Direct(0x12345 + start_of_fde1.value().unwrap())
6643 )))
6644 );
6645
6646 assert_eq!(
6647 table.iter(&bases).nth(1),
6648 Ok(Some((
6649 Pointer::Direct(20),
6650 Pointer::Direct(0x12345 + start_of_fde2.value().unwrap())
6651 )))
6652 );
6653 assert_eq!(table.iter(&bases).nth(2), Ok(None));
6654
6655 let f = |_: &_, _: &_, o: EhFrameOffset| {
6656 assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6657 Ok(cie.clone())
6658 };
6659 assert_eq!(
6660 table.fde_for_address(&eh_frame, &bases, 9, f),
6661 Ok(fde1.clone())
6662 );
6663 assert_eq!(
6664 table.fde_for_address(&eh_frame, &bases, 10, f),
6665 Ok(fde1.clone())
6666 );
6667 assert_eq!(table.fde_for_address(&eh_frame, &bases, 11, f), Ok(fde1));
6668 assert_eq!(
6669 table.fde_for_address(&eh_frame, &bases, 19, f),
6670 Err(Error::NoUnwindInfoForAddress)
6671 );
6672 assert_eq!(
6673 table.fde_for_address(&eh_frame, &bases, 20, f),
6674 Ok(fde2.clone())
6675 );
6676 assert_eq!(table.fde_for_address(&eh_frame, &bases, 21, f), Ok(fde2));
6677 assert_eq!(
6678 table.fde_for_address(&eh_frame, &bases, 100_000, f),
6679 Err(Error::NoUnwindInfoForAddress)
6680 );
6681 }
6682
6683 #[test]
6684 fn test_eh_frame_stops_at_zero_length() {
6685 let mut cie = make_test_cie();
6686 let kind = eh_frame_le();
6687 let section = Section::with_endian(Endian::Little)
6688 .L32(0)
6689 .cie(kind, None, &mut cie)
6690 .L32(0);
6691 let contents = section.get_contents().unwrap();
6692 let eh_frame = kind.section(&contents);
6693 let bases = Default::default();
6694
6695 let mut entries = eh_frame.entries(&bases);
6696 assert_eq!(entries.next(), Ok(None));
6697
6698 assert_eq!(
6699 eh_frame.cie_from_offset(&bases, EhFrameOffset(0)),
6700 Err(Error::NoEntryAtGivenOffset)
6701 );
6702 }
6703
6704 #[test]
6705 fn test_debug_frame_skips_zero_length() {
6706 let mut cie = make_test_cie();
6707 let kind = debug_frame_le();
6708 let section = Section::with_endian(Endian::Little)
6709 .L32(0)
6710 .cie(kind, None, &mut cie)
6711 .L32(0);
6712 let contents = section.get_contents().unwrap();
6713 let debug_frame = kind.section(&contents);
6714 let bases = Default::default();
6715
6716 let mut entries = debug_frame.entries(&bases);
6717 assert_eq!(entries.next(), Ok(Some(CieOrFde::Cie(cie))));
6718 assert_eq!(entries.next(), Ok(None));
6719
6720 assert_eq!(
6721 debug_frame.cie_from_offset(&bases, DebugFrameOffset(0)),
6722 Err(Error::NoEntryAtGivenOffset)
6723 );
6724 }
6725
6726 fn resolve_cie_offset(buf: &[u8], cie_offset: usize) -> Result<usize> {
6727 let mut fde = FrameDescriptionEntry {
6728 offset: 0,
6729 length: 0,
6730 format: Format::Dwarf64,
6731 cie: make_test_cie(),
6732 initial_address: 0xfeed_beef,
6733 address_range: 39,
6734 augmentation: None,
6735 instructions: EndianSlice::new(&[], LittleEndian),
6736 };
6737
6738 let kind = eh_frame_le();
6739 let section = Section::with_endian(kind.endian())
6740 .append_bytes(buf)
6741 .fde(kind, cie_offset as u64, &mut fde)
6742 .append_bytes(buf);
6743
6744 let section = section.get_contents().unwrap();
6745 let eh_frame = kind.section(§ion);
6746 let input = &mut EndianSlice::new(§ion[buf.len()..], LittleEndian);
6747
6748 let bases = Default::default();
6749 match parse_cfi_entry(&bases, &eh_frame, input) {
6750 Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0),
6751 Err(e) => Err(e),
6752 otherwise => panic!("Unexpected result: {:#?}", otherwise),
6753 }
6754 }
6755
6756 #[test]
6757 fn test_eh_frame_resolve_cie_offset_ok() {
6758 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6759 let cie_offset = 2;
6760 assert_eq!(
6762 resolve_cie_offset(&buf, buf.len() + 4 - cie_offset),
6763 Ok(cie_offset)
6764 );
6765 }
6766
6767 #[test]
6768 fn test_eh_frame_resolve_cie_offset_out_of_bounds() {
6769 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6770 assert_eq!(
6771 resolve_cie_offset(&buf, buf.len() + 4 + 2),
6772 Err(Error::OffsetOutOfBounds)
6773 );
6774 }
6775
6776 #[test]
6777 fn test_eh_frame_resolve_cie_offset_underflow() {
6778 let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
6779 assert_eq!(
6780 resolve_cie_offset(&buf, usize::MAX),
6781 Err(Error::OffsetOutOfBounds)
6782 );
6783 }
6784
6785 #[test]
6786 fn test_eh_frame_fde_ok() {
6787 let mut cie = make_test_cie();
6788 cie.format = Format::Dwarf32;
6789 cie.version = 1;
6790
6791 let start_of_cie = Label::new();
6792 let end_of_cie = Label::new();
6793
6794 let kind = eh_frame_le();
6797 let section = Section::with_endian(kind.endian())
6798 .append_repeated(0, 16)
6799 .mark(&start_of_cie)
6800 .cie(kind, None, &mut cie)
6801 .mark(&end_of_cie);
6802
6803 let mut fde = FrameDescriptionEntry {
6804 offset: 0,
6805 length: 0,
6806 format: Format::Dwarf32,
6807 cie: cie.clone(),
6808 initial_address: 0xfeed_beef,
6809 address_range: 999,
6810 augmentation: None,
6811 instructions: EndianSlice::new(&[], LittleEndian),
6812 };
6813
6814 let section = section
6815 .fde(kind, (&end_of_cie - &start_of_cie + 4) as u64, &mut fde);
6817
6818 section.start().set_const(0);
6819 let section = section.get_contents().unwrap();
6820 let eh_frame = kind.section(§ion);
6821 let section = EndianSlice::new(§ion, LittleEndian);
6822
6823 let mut offset = None;
6824 let result = parse_fde(
6825 eh_frame,
6826 &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6827 |_, _, o| {
6828 offset = Some(o);
6829 assert_eq!(o, EhFrameOffset(start_of_cie.value().unwrap() as usize));
6830 Ok(cie.clone())
6831 },
6832 );
6833 match result {
6834 Ok(actual) => assert_eq!(actual, fde),
6835 otherwise => panic!("Unexpected result {:?}", otherwise),
6836 }
6837 assert!(offset.is_some());
6838 }
6839
6840 #[test]
6841 fn test_eh_frame_fde_out_of_bounds() {
6842 let mut cie = make_test_cie();
6843 cie.version = 1;
6844
6845 let end_of_cie = Label::new();
6846
6847 let mut fde = FrameDescriptionEntry {
6848 offset: 0,
6849 length: 0,
6850 format: Format::Dwarf64,
6851 cie: cie.clone(),
6852 initial_address: 0xfeed_beef,
6853 address_range: 999,
6854 augmentation: None,
6855 instructions: EndianSlice::new(&[], LittleEndian),
6856 };
6857
6858 let kind = eh_frame_le();
6859 let section = Section::with_endian(kind.endian())
6860 .cie(kind, None, &mut cie)
6861 .mark(&end_of_cie)
6862 .fde(kind, 99_999_999_999_999, &mut fde);
6863
6864 section.start().set_const(0);
6865 let section = section.get_contents().unwrap();
6866 let eh_frame = kind.section(§ion);
6867 let section = EndianSlice::new(§ion, LittleEndian);
6868
6869 let result = parse_fde(
6870 eh_frame,
6871 &mut section.range_from(end_of_cie.value().unwrap() as usize..),
6872 UnwindSection::cie_from_offset,
6873 );
6874 assert_eq!(result, Err(Error::OffsetOutOfBounds));
6875 }
6876
6877 #[test]
6878 fn test_augmentation_parse_not_z_augmentation() {
6879 let augmentation = &mut EndianSlice::new(b"wtf", NativeEndian);
6880 let bases = Default::default();
6881 let address_size = 8;
6882 let section = EhFrame::new(&[], NativeEndian);
6883 let input = &mut EndianSlice::new(&[], NativeEndian);
6884 assert_eq!(
6885 Augmentation::parse(augmentation, &bases, address_size, §ion, input),
6886 Err(Error::UnknownAugmentation)
6887 );
6888 }
6889
6890 #[test]
6891 fn test_augmentation_parse_just_signal_trampoline() {
6892 let aug_str = &mut EndianSlice::new(b"S", LittleEndian);
6893 let bases = Default::default();
6894 let address_size = 8;
6895 let section = EhFrame::new(&[], LittleEndian);
6896 let input = &mut EndianSlice::new(&[], LittleEndian);
6897
6898 let augmentation = Augmentation {
6899 is_signal_trampoline: true,
6900 ..Default::default()
6901 };
6902
6903 assert_eq!(
6904 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6905 Ok(augmentation)
6906 );
6907 }
6908
6909 #[test]
6910 fn test_augmentation_parse_unknown_part_of_z_augmentation() {
6911 let bases = Default::default();
6913 let address_size = 8;
6914 let section = Section::with_endian(Endian::Little)
6915 .uleb(4)
6916 .append_repeated(4, 4)
6917 .get_contents()
6918 .unwrap();
6919 let section = EhFrame::new(§ion, LittleEndian);
6920 let input = &mut section.section().clone();
6921 let augmentation = &mut EndianSlice::new(b"zZ", LittleEndian);
6922 assert_eq!(
6923 Augmentation::parse(augmentation, &bases, address_size, §ion, input),
6924 Err(Error::UnknownAugmentation)
6925 );
6926 }
6927
6928 #[test]
6929 #[allow(non_snake_case)]
6930 fn test_augmentation_parse_L() {
6931 let bases = Default::default();
6932 let address_size = 8;
6933 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6934
6935 let section = Section::with_endian(Endian::Little)
6936 .uleb(1)
6937 .D8(constants::DW_EH_PE_uleb128.0)
6938 .append_bytes(&rest)
6939 .get_contents()
6940 .unwrap();
6941 let section = EhFrame::new(§ion, LittleEndian);
6942 let input = &mut section.section().clone();
6943 let aug_str = &mut EndianSlice::new(b"zL", LittleEndian);
6944
6945 let augmentation = Augmentation {
6946 lsda: Some(constants::DW_EH_PE_uleb128),
6947 ..Default::default()
6948 };
6949
6950 assert_eq!(
6951 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6952 Ok(augmentation)
6953 );
6954 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6955 }
6956
6957 #[test]
6958 #[allow(non_snake_case)]
6959 fn test_augmentation_parse_P() {
6960 let bases = Default::default();
6961 let address_size = 8;
6962 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6963
6964 let section = Section::with_endian(Endian::Little)
6965 .uleb(9)
6966 .D8(constants::DW_EH_PE_udata8.0)
6967 .L64(0xf00d_f00d)
6968 .append_bytes(&rest)
6969 .get_contents()
6970 .unwrap();
6971 let section = EhFrame::new(§ion, LittleEndian);
6972 let input = &mut section.section().clone();
6973 let aug_str = &mut EndianSlice::new(b"zP", LittleEndian);
6974
6975 let augmentation = Augmentation {
6976 personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0xf00d_f00d))),
6977 ..Default::default()
6978 };
6979
6980 assert_eq!(
6981 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
6982 Ok(augmentation)
6983 );
6984 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
6985 }
6986
6987 #[test]
6988 #[allow(non_snake_case)]
6989 fn test_augmentation_parse_R() {
6990 let bases = Default::default();
6991 let address_size = 8;
6992 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
6993
6994 let section = Section::with_endian(Endian::Little)
6995 .uleb(1)
6996 .D8(constants::DW_EH_PE_udata4.0)
6997 .append_bytes(&rest)
6998 .get_contents()
6999 .unwrap();
7000 let section = EhFrame::new(§ion, LittleEndian);
7001 let input = &mut section.section().clone();
7002 let aug_str = &mut EndianSlice::new(b"zR", LittleEndian);
7003
7004 let augmentation = Augmentation {
7005 fde_address_encoding: Some(constants::DW_EH_PE_udata4),
7006 ..Default::default()
7007 };
7008
7009 assert_eq!(
7010 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
7011 Ok(augmentation)
7012 );
7013 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7014 }
7015
7016 #[test]
7017 #[allow(non_snake_case)]
7018 fn test_augmentation_parse_S() {
7019 let bases = Default::default();
7020 let address_size = 8;
7021 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7022
7023 let section = Section::with_endian(Endian::Little)
7024 .uleb(0)
7025 .append_bytes(&rest)
7026 .get_contents()
7027 .unwrap();
7028 let section = EhFrame::new(§ion, LittleEndian);
7029 let input = &mut section.section().clone();
7030 let aug_str = &mut EndianSlice::new(b"zS", LittleEndian);
7031
7032 let augmentation = Augmentation {
7033 is_signal_trampoline: true,
7034 ..Default::default()
7035 };
7036
7037 assert_eq!(
7038 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
7039 Ok(augmentation)
7040 );
7041 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7042 }
7043
7044 #[test]
7045 fn test_augmentation_parse_all() {
7046 let bases = Default::default();
7047 let address_size = 8;
7048 let rest = [9, 8, 7, 6, 5, 4, 3, 2, 1];
7049
7050 let section = Section::with_endian(Endian::Little)
7051 .uleb(1 + 9 + 1)
7052 .D8(constants::DW_EH_PE_uleb128.0)
7054 .D8(constants::DW_EH_PE_udata8.0)
7056 .L64(0x1bad_f00d)
7057 .D8(constants::DW_EH_PE_uleb128.0)
7059 .append_bytes(&rest)
7060 .get_contents()
7061 .unwrap();
7062 let section = EhFrame::new(§ion, LittleEndian);
7063 let input = &mut section.section().clone();
7064 let aug_str = &mut EndianSlice::new(b"zLPRS", LittleEndian);
7065
7066 let augmentation = Augmentation {
7067 lsda: Some(constants::DW_EH_PE_uleb128),
7068 personality: Some((constants::DW_EH_PE_udata8, Pointer::Direct(0x1bad_f00d))),
7069 fde_address_encoding: Some(constants::DW_EH_PE_uleb128),
7070 is_signal_trampoline: true,
7071 };
7072
7073 assert_eq!(
7074 Augmentation::parse(aug_str, &bases, address_size, §ion, input),
7075 Ok(augmentation)
7076 );
7077 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7078 }
7079
7080 #[test]
7081 fn test_eh_frame_fde_no_augmentation() {
7082 let instrs = [1, 2, 3, 4];
7083 let cie_offset = 1;
7084
7085 let mut cie = make_test_cie();
7086 cie.format = Format::Dwarf32;
7087 cie.version = 1;
7088
7089 let mut fde = FrameDescriptionEntry {
7090 offset: 0,
7091 length: 0,
7092 format: Format::Dwarf32,
7093 cie: cie.clone(),
7094 initial_address: 0xfeed_face,
7095 address_range: 9000,
7096 augmentation: None,
7097 instructions: EndianSlice::new(&instrs, LittleEndian),
7098 };
7099
7100 let rest = [1, 2, 3, 4];
7101
7102 let kind = eh_frame_le();
7103 let section = Section::with_endian(kind.endian())
7104 .fde(kind, cie_offset, &mut fde)
7105 .append_bytes(&rest)
7106 .get_contents()
7107 .unwrap();
7108 let section = kind.section(§ion);
7109 let input = &mut section.section().clone();
7110
7111 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7112 assert_eq!(result, Ok(fde));
7113 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7114 }
7115
7116 #[test]
7117 fn test_eh_frame_fde_empty_augmentation() {
7118 let instrs = [1, 2, 3, 4];
7119 let cie_offset = 1;
7120
7121 let mut cie = make_test_cie();
7122 cie.format = Format::Dwarf32;
7123 cie.version = 1;
7124 cie.augmentation = Some(Augmentation::default());
7125
7126 let mut fde = FrameDescriptionEntry {
7127 offset: 0,
7128 length: 0,
7129 format: Format::Dwarf32,
7130 cie: cie.clone(),
7131 initial_address: 0xfeed_face,
7132 address_range: 9000,
7133 augmentation: Some(AugmentationData::default()),
7134 instructions: EndianSlice::new(&instrs, LittleEndian),
7135 };
7136
7137 let rest = [1, 2, 3, 4];
7138
7139 let kind = eh_frame_le();
7140 let section = Section::with_endian(kind.endian())
7141 .fde(kind, cie_offset, &mut fde)
7142 .append_bytes(&rest)
7143 .get_contents()
7144 .unwrap();
7145 let section = kind.section(§ion);
7146 let input = &mut section.section().clone();
7147
7148 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7149 assert_eq!(result, Ok(fde));
7150 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7151 }
7152
7153 #[test]
7154 fn test_eh_frame_fde_lsda_augmentation() {
7155 let instrs = [1, 2, 3, 4];
7156 let cie_offset = 1;
7157
7158 let mut cie = make_test_cie();
7159 cie.format = Format::Dwarf32;
7160 cie.version = 1;
7161 cie.augmentation = Some(Augmentation::default());
7162 cie.augmentation.as_mut().unwrap().lsda = Some(constants::DW_EH_PE_absptr);
7163
7164 let mut fde = FrameDescriptionEntry {
7165 offset: 0,
7166 length: 0,
7167 format: Format::Dwarf32,
7168 cie: cie.clone(),
7169 initial_address: 0xfeed_face,
7170 address_range: 9000,
7171 augmentation: Some(AugmentationData {
7172 lsda: Some(Pointer::Direct(0x1122_3344)),
7173 }),
7174 instructions: EndianSlice::new(&instrs, LittleEndian),
7175 };
7176
7177 let rest = [1, 2, 3, 4];
7178
7179 let kind = eh_frame_le();
7180 let section = Section::with_endian(kind.endian())
7181 .fde(kind, cie_offset, &mut fde)
7182 .append_bytes(&rest)
7183 .get_contents()
7184 .unwrap();
7185 let section = kind.section(§ion);
7186 let input = &mut section.section().clone();
7187
7188 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7189 assert_eq!(result, Ok(fde));
7190 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7191 }
7192
7193 #[test]
7194 fn test_eh_frame_fde_lsda_function_relative() {
7195 let instrs = [1, 2, 3, 4];
7196 let cie_offset = 1;
7197
7198 let mut cie = make_test_cie();
7199 cie.format = Format::Dwarf32;
7200 cie.version = 1;
7201 cie.augmentation = Some(Augmentation::default());
7202 cie.augmentation.as_mut().unwrap().lsda =
7203 Some(constants::DW_EH_PE_funcrel | constants::DW_EH_PE_absptr);
7204
7205 let mut fde = FrameDescriptionEntry {
7206 offset: 0,
7207 length: 0,
7208 format: Format::Dwarf32,
7209 cie: cie.clone(),
7210 initial_address: 0xfeed_face,
7211 address_range: 9000,
7212 augmentation: Some(AugmentationData {
7213 lsda: Some(Pointer::Direct(0xbeef)),
7214 }),
7215 instructions: EndianSlice::new(&instrs, LittleEndian),
7216 };
7217
7218 let rest = [1, 2, 3, 4];
7219
7220 let kind = eh_frame_le();
7221 let section = Section::with_endian(kind.endian())
7222 .append_repeated(10, 10)
7223 .fde(kind, cie_offset, &mut fde)
7224 .append_bytes(&rest)
7225 .get_contents()
7226 .unwrap();
7227 let section = kind.section(§ion);
7228 let input = &mut section.section().range_from(10..);
7229
7230 fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef));
7232
7233 let result = parse_fde(section, input, |_, _, _| Ok(cie.clone()));
7234 assert_eq!(result, Ok(fde));
7235 assert_eq!(*input, EndianSlice::new(&rest, LittleEndian));
7236 }
7237
7238 #[test]
7239 fn test_eh_frame_cie_personality_function_relative_bad_context() {
7240 let instrs = [1, 2, 3, 4];
7241
7242 let length = Label::new();
7243 let start = Label::new();
7244 let end = Label::new();
7245
7246 let aug_len = Label::new();
7247 let aug_start = Label::new();
7248 let aug_end = Label::new();
7249
7250 let section = Section::with_endian(Endian::Little)
7251 .L32(&length)
7253 .mark(&start)
7254 .L32(0)
7256 .D8(1)
7258 .append_bytes(b"zP\0")
7260 .uleb(1)
7262 .sleb(1)
7264 .uleb(1)
7266 .D8(&aug_len)
7270 .mark(&aug_start)
7271 .D8(constants::DW_EH_PE_funcrel.0 | constants::DW_EH_PE_uleb128.0)
7273 .uleb(1)
7274 .mark(&aug_end)
7275 .append_bytes(&instrs)
7277 .mark(&end);
7278
7279 length.set_const((&end - &start) as u64);
7280 aug_len.set_const((&aug_end - &aug_start) as u64);
7281
7282 let section = section.get_contents().unwrap();
7283 let section = EhFrame::new(§ion, LittleEndian);
7284
7285 let bases = BaseAddresses::default();
7286 let mut iter = section.entries(&bases);
7287 assert_eq!(iter.next(), Err(Error::FuncRelativePointerInBadContext));
7288 }
7289
7290 #[test]
7291 fn register_rule_map_eq() {
7292 let map1: RegisterRuleMap<usize> = [
7294 (Register(0), RegisterRule::SameValue),
7295 (Register(3), RegisterRule::Offset(1)),
7296 ]
7297 .iter()
7298 .collect();
7299 let map2: RegisterRuleMap<usize> = [
7300 (Register(3), RegisterRule::Offset(1)),
7301 (Register(0), RegisterRule::SameValue),
7302 ]
7303 .iter()
7304 .collect();
7305 assert_eq!(map1, map2);
7306 assert_eq!(map2, map1);
7307
7308 let map3: RegisterRuleMap<usize> = [
7310 (Register(0), RegisterRule::SameValue),
7311 (Register(2), RegisterRule::Offset(1)),
7312 ]
7313 .iter()
7314 .collect();
7315 let map4: RegisterRuleMap<usize> = [
7316 (Register(3), RegisterRule::Offset(1)),
7317 (Register(0), RegisterRule::SameValue),
7318 ]
7319 .iter()
7320 .collect();
7321 assert!(map3 != map4);
7322 assert!(map4 != map3);
7323
7324 let mut map5 = RegisterRuleMap::<usize>::default();
7326 map5.set(Register(0), RegisterRule::SameValue).unwrap();
7327 map5.set(Register(0), RegisterRule::Undefined).unwrap();
7328 let map6 = RegisterRuleMap::<usize>::default();
7329 assert_eq!(map5, map6);
7330 assert_eq!(map6, map5);
7331 }
7332
7333 #[test]
7334 fn iter_register_rules() {
7335 let row = UnwindTableRow::<usize> {
7336 registers: [
7337 (Register(0), RegisterRule::SameValue),
7338 (Register(1), RegisterRule::Offset(1)),
7339 (Register(2), RegisterRule::ValOffset(2)),
7340 ]
7341 .iter()
7342 .collect(),
7343 ..Default::default()
7344 };
7345
7346 let mut found0 = false;
7347 let mut found1 = false;
7348 let mut found2 = false;
7349
7350 for &(register, ref rule) in row.registers() {
7351 match register.0 {
7352 0 => {
7353 assert!(!found0);
7354 found0 = true;
7355 assert_eq!(*rule, RegisterRule::SameValue);
7356 }
7357 1 => {
7358 assert!(!found1);
7359 found1 = true;
7360 assert_eq!(*rule, RegisterRule::Offset(1));
7361 }
7362 2 => {
7363 assert!(!found2);
7364 found2 = true;
7365 assert_eq!(*rule, RegisterRule::ValOffset(2));
7366 }
7367 x => panic!("Unexpected register rule: ({}, {:?})", x, rule),
7368 }
7369 }
7370
7371 assert!(found0);
7372 assert!(found1);
7373 assert!(found2);
7374 }
7375
7376 #[test]
7377 #[cfg(target_pointer_width = "64")]
7378 fn size_of_unwind_ctx() {
7379 use core::mem;
7380 let size = mem::size_of::<UnwindContext<usize>>();
7381 let max_size = 30968;
7382 if size > max_size {
7383 assert_eq!(size, max_size);
7384 }
7385 }
7386
7387 #[test]
7388 #[cfg(target_pointer_width = "64")]
7389 fn size_of_register_rule_map() {
7390 use core::mem;
7391 let size = mem::size_of::<RegisterRuleMap<usize>>();
7392 let max_size = 6152;
7393 if size > max_size {
7394 assert_eq!(size, max_size);
7395 }
7396 }
7397
7398 #[test]
7399 fn test_parse_pointer_encoding_ok() {
7400 use crate::endianity::NativeEndian;
7401 let expected = constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_pcrel;
7402 let input = [expected.0, 1, 2, 3, 4];
7403 let input = &mut EndianSlice::new(&input, NativeEndian);
7404 assert_eq!(parse_pointer_encoding(input), Ok(expected));
7405 assert_eq!(*input, EndianSlice::new(&[1, 2, 3, 4], NativeEndian));
7406 }
7407
7408 #[test]
7409 fn test_parse_pointer_encoding_bad_encoding() {
7410 use crate::endianity::NativeEndian;
7411 let expected =
7412 constants::DwEhPe((constants::DW_EH_PE_sdata8.0 + 1) | constants::DW_EH_PE_pcrel.0);
7413 let input = [expected.0, 1, 2, 3, 4];
7414 let input = &mut EndianSlice::new(&input, NativeEndian);
7415 assert_eq!(
7416 Err(Error::UnknownPointerEncoding(expected)),
7417 parse_pointer_encoding(input)
7418 );
7419 }
7420
7421 #[test]
7422 fn test_parse_encoded_pointer_absptr() {
7423 let encoding = constants::DW_EH_PE_absptr;
7424 let expected_rest = [1, 2, 3, 4];
7425
7426 let input = Section::with_endian(Endian::Little)
7427 .L32(0xf00d_f00d)
7428 .append_bytes(&expected_rest);
7429 let input = input.get_contents().unwrap();
7430 let input = EndianSlice::new(&input, LittleEndian);
7431 let mut rest = input;
7432
7433 let parameters = PointerEncodingParameters {
7434 bases: &SectionBaseAddresses::default(),
7435 func_base: None,
7436 address_size: 4,
7437 section: &input,
7438 };
7439 assert_eq!(
7440 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7441 Ok(Pointer::Direct(0xf00d_f00d))
7442 );
7443 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7444 }
7445
7446 #[test]
7447 fn test_parse_encoded_pointer_pcrel() {
7448 let encoding = constants::DW_EH_PE_pcrel;
7449 let expected_rest = [1, 2, 3, 4];
7450
7451 let input = Section::with_endian(Endian::Little)
7452 .append_repeated(0, 0x10)
7453 .L32(0x1)
7454 .append_bytes(&expected_rest);
7455 let input = input.get_contents().unwrap();
7456 let input = EndianSlice::new(&input, LittleEndian);
7457 let mut rest = input.range_from(0x10..);
7458
7459 let parameters = PointerEncodingParameters {
7460 bases: &BaseAddresses::default().set_eh_frame(0x100).eh_frame,
7461 func_base: None,
7462 address_size: 4,
7463 section: &input,
7464 };
7465 assert_eq!(
7466 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7467 Ok(Pointer::Direct(0x111))
7468 );
7469 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7470 }
7471
7472 #[test]
7473 fn test_parse_encoded_pointer_pcrel_undefined() {
7474 let encoding = constants::DW_EH_PE_pcrel;
7475
7476 let input = Section::with_endian(Endian::Little).L32(0x1);
7477 let input = input.get_contents().unwrap();
7478 let input = EndianSlice::new(&input, LittleEndian);
7479 let mut rest = input;
7480
7481 let parameters = PointerEncodingParameters {
7482 bases: &SectionBaseAddresses::default(),
7483 func_base: None,
7484 address_size: 4,
7485 section: &input,
7486 };
7487 assert_eq!(
7488 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7489 Err(Error::PcRelativePointerButSectionBaseIsUndefined)
7490 );
7491 }
7492
7493 #[test]
7494 fn test_parse_encoded_pointer_textrel() {
7495 let encoding = constants::DW_EH_PE_textrel;
7496 let expected_rest = [1, 2, 3, 4];
7497
7498 let input = Section::with_endian(Endian::Little)
7499 .L32(0x1)
7500 .append_bytes(&expected_rest);
7501 let input = input.get_contents().unwrap();
7502 let input = EndianSlice::new(&input, LittleEndian);
7503 let mut rest = input;
7504
7505 let parameters = PointerEncodingParameters {
7506 bases: &BaseAddresses::default().set_text(0x10).eh_frame,
7507 func_base: None,
7508 address_size: 4,
7509 section: &input,
7510 };
7511 assert_eq!(
7512 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7513 Ok(Pointer::Direct(0x11))
7514 );
7515 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7516 }
7517
7518 #[test]
7519 fn test_parse_encoded_pointer_textrel_undefined() {
7520 let encoding = constants::DW_EH_PE_textrel;
7521
7522 let input = Section::with_endian(Endian::Little).L32(0x1);
7523 let input = input.get_contents().unwrap();
7524 let input = EndianSlice::new(&input, LittleEndian);
7525 let mut rest = input;
7526
7527 let parameters = PointerEncodingParameters {
7528 bases: &SectionBaseAddresses::default(),
7529 func_base: None,
7530 address_size: 4,
7531 section: &input,
7532 };
7533 assert_eq!(
7534 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7535 Err(Error::TextRelativePointerButTextBaseIsUndefined)
7536 );
7537 }
7538
7539 #[test]
7540 fn test_parse_encoded_pointer_datarel() {
7541 let encoding = constants::DW_EH_PE_datarel;
7542 let expected_rest = [1, 2, 3, 4];
7543
7544 let input = Section::with_endian(Endian::Little)
7545 .L32(0x1)
7546 .append_bytes(&expected_rest);
7547 let input = input.get_contents().unwrap();
7548 let input = EndianSlice::new(&input, LittleEndian);
7549 let mut rest = input;
7550
7551 let parameters = PointerEncodingParameters {
7552 bases: &BaseAddresses::default().set_got(0x10).eh_frame,
7553 func_base: None,
7554 address_size: 4,
7555 section: &input,
7556 };
7557 assert_eq!(
7558 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7559 Ok(Pointer::Direct(0x11))
7560 );
7561 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7562 }
7563
7564 #[test]
7565 fn test_parse_encoded_pointer_datarel_undefined() {
7566 let encoding = constants::DW_EH_PE_datarel;
7567
7568 let input = Section::with_endian(Endian::Little).L32(0x1);
7569 let input = input.get_contents().unwrap();
7570 let input = EndianSlice::new(&input, LittleEndian);
7571 let mut rest = input;
7572
7573 let parameters = PointerEncodingParameters {
7574 bases: &SectionBaseAddresses::default(),
7575 func_base: None,
7576 address_size: 4,
7577 section: &input,
7578 };
7579 assert_eq!(
7580 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7581 Err(Error::DataRelativePointerButDataBaseIsUndefined)
7582 );
7583 }
7584
7585 #[test]
7586 fn test_parse_encoded_pointer_funcrel() {
7587 let encoding = constants::DW_EH_PE_funcrel;
7588 let expected_rest = [1, 2, 3, 4];
7589
7590 let input = Section::with_endian(Endian::Little)
7591 .L32(0x1)
7592 .append_bytes(&expected_rest);
7593 let input = input.get_contents().unwrap();
7594 let input = EndianSlice::new(&input, LittleEndian);
7595 let mut rest = input;
7596
7597 let parameters = PointerEncodingParameters {
7598 bases: &SectionBaseAddresses::default(),
7599 func_base: Some(0x10),
7600 address_size: 4,
7601 section: &input,
7602 };
7603 assert_eq!(
7604 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7605 Ok(Pointer::Direct(0x11))
7606 );
7607 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7608 }
7609
7610 #[test]
7611 fn test_parse_encoded_pointer_funcrel_undefined() {
7612 let encoding = constants::DW_EH_PE_funcrel;
7613
7614 let input = Section::with_endian(Endian::Little).L32(0x1);
7615 let input = input.get_contents().unwrap();
7616 let input = EndianSlice::new(&input, LittleEndian);
7617 let mut rest = input;
7618
7619 let parameters = PointerEncodingParameters {
7620 bases: &SectionBaseAddresses::default(),
7621 func_base: None,
7622 address_size: 4,
7623 section: &input,
7624 };
7625 assert_eq!(
7626 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7627 Err(Error::FuncRelativePointerInBadContext)
7628 );
7629 }
7630
7631 #[test]
7632 fn test_parse_encoded_pointer_uleb128() {
7633 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_uleb128;
7634 let expected_rest = [1, 2, 3, 4];
7635
7636 let input = Section::with_endian(Endian::Little)
7637 .uleb(0x12_3456)
7638 .append_bytes(&expected_rest);
7639 let input = input.get_contents().unwrap();
7640 let input = EndianSlice::new(&input, LittleEndian);
7641 let mut rest = input;
7642
7643 let parameters = PointerEncodingParameters {
7644 bases: &SectionBaseAddresses::default(),
7645 func_base: None,
7646 address_size: 4,
7647 section: &input,
7648 };
7649 assert_eq!(
7650 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7651 Ok(Pointer::Direct(0x12_3456))
7652 );
7653 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7654 }
7655
7656 #[test]
7657 fn test_parse_encoded_pointer_udata2() {
7658 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata2;
7659 let expected_rest = [1, 2, 3, 4];
7660
7661 let input = Section::with_endian(Endian::Little)
7662 .L16(0x1234)
7663 .append_bytes(&expected_rest);
7664 let input = input.get_contents().unwrap();
7665 let input = EndianSlice::new(&input, LittleEndian);
7666 let mut rest = input;
7667
7668 let parameters = PointerEncodingParameters {
7669 bases: &SectionBaseAddresses::default(),
7670 func_base: None,
7671 address_size: 4,
7672 section: &input,
7673 };
7674 assert_eq!(
7675 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7676 Ok(Pointer::Direct(0x1234))
7677 );
7678 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7679 }
7680
7681 #[test]
7682 fn test_parse_encoded_pointer_udata4() {
7683 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata4;
7684 let expected_rest = [1, 2, 3, 4];
7685
7686 let input = Section::with_endian(Endian::Little)
7687 .L32(0x1234_5678)
7688 .append_bytes(&expected_rest);
7689 let input = input.get_contents().unwrap();
7690 let input = EndianSlice::new(&input, LittleEndian);
7691 let mut rest = input;
7692
7693 let parameters = PointerEncodingParameters {
7694 bases: &SectionBaseAddresses::default(),
7695 func_base: None,
7696 address_size: 4,
7697 section: &input,
7698 };
7699 assert_eq!(
7700 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7701 Ok(Pointer::Direct(0x1234_5678))
7702 );
7703 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7704 }
7705
7706 #[test]
7707 fn test_parse_encoded_pointer_udata8() {
7708 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_udata8;
7709 let expected_rest = [1, 2, 3, 4];
7710
7711 let input = Section::with_endian(Endian::Little)
7712 .L64(0x1234_5678_1234_5678)
7713 .append_bytes(&expected_rest);
7714 let input = input.get_contents().unwrap();
7715 let input = EndianSlice::new(&input, LittleEndian);
7716 let mut rest = input;
7717
7718 let parameters = PointerEncodingParameters {
7719 bases: &SectionBaseAddresses::default(),
7720 func_base: None,
7721 address_size: 8,
7722 section: &input,
7723 };
7724 assert_eq!(
7725 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7726 Ok(Pointer::Direct(0x1234_5678_1234_5678))
7727 );
7728 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7729 }
7730
7731 #[test]
7732 fn test_parse_encoded_pointer_sleb128() {
7733 let encoding = constants::DW_EH_PE_textrel | constants::DW_EH_PE_sleb128;
7734 let expected_rest = [1, 2, 3, 4];
7735
7736 let input = Section::with_endian(Endian::Little)
7737 .sleb(-0x1111)
7738 .append_bytes(&expected_rest);
7739 let input = input.get_contents().unwrap();
7740 let input = EndianSlice::new(&input, LittleEndian);
7741 let mut rest = input;
7742
7743 let parameters = PointerEncodingParameters {
7744 bases: &BaseAddresses::default().set_text(0x1111_1111).eh_frame,
7745 func_base: None,
7746 address_size: 4,
7747 section: &input,
7748 };
7749 assert_eq!(
7750 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7751 Ok(Pointer::Direct(0x1111_0000))
7752 );
7753 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7754 }
7755
7756 #[test]
7757 fn test_parse_encoded_pointer_sdata2() {
7758 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata2;
7759 let expected_rest = [1, 2, 3, 4];
7760 let expected = 0x111_i16;
7761
7762 let input = Section::with_endian(Endian::Little)
7763 .L16(expected as u16)
7764 .append_bytes(&expected_rest);
7765 let input = input.get_contents().unwrap();
7766 let input = EndianSlice::new(&input, LittleEndian);
7767 let mut rest = input;
7768
7769 let parameters = PointerEncodingParameters {
7770 bases: &SectionBaseAddresses::default(),
7771 func_base: None,
7772 address_size: 4,
7773 section: &input,
7774 };
7775 assert_eq!(
7776 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7777 Ok(Pointer::Direct(expected as u64))
7778 );
7779 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7780 }
7781
7782 #[test]
7783 fn test_parse_encoded_pointer_sdata4() {
7784 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata4;
7785 let expected_rest = [1, 2, 3, 4];
7786 let expected = 0x111_1111_i32;
7787
7788 let input = Section::with_endian(Endian::Little)
7789 .L32(expected as u32)
7790 .append_bytes(&expected_rest);
7791 let input = input.get_contents().unwrap();
7792 let input = EndianSlice::new(&input, LittleEndian);
7793 let mut rest = input;
7794
7795 let parameters = PointerEncodingParameters {
7796 bases: &SectionBaseAddresses::default(),
7797 func_base: None,
7798 address_size: 4,
7799 section: &input,
7800 };
7801 assert_eq!(
7802 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7803 Ok(Pointer::Direct(expected as u64))
7804 );
7805 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7806 }
7807
7808 #[test]
7809 fn test_parse_encoded_pointer_sdata8() {
7810 let encoding = constants::DW_EH_PE_absptr | constants::DW_EH_PE_sdata8;
7811 let expected_rest = [1, 2, 3, 4];
7812 let expected = -0x11_1111_1222_2222_i64;
7813
7814 let input = Section::with_endian(Endian::Little)
7815 .L64(expected as u64)
7816 .append_bytes(&expected_rest);
7817 let input = input.get_contents().unwrap();
7818 let input = EndianSlice::new(&input, LittleEndian);
7819 let mut rest = input;
7820
7821 let parameters = PointerEncodingParameters {
7822 bases: &SectionBaseAddresses::default(),
7823 func_base: None,
7824 address_size: 8,
7825 section: &input,
7826 };
7827 assert_eq!(
7828 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7829 Ok(Pointer::Direct(expected as u64))
7830 );
7831 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7832 }
7833
7834 #[test]
7835 fn test_parse_encoded_pointer_omit() {
7836 let encoding = constants::DW_EH_PE_omit;
7837
7838 let input = Section::with_endian(Endian::Little).L32(0x1);
7839 let input = input.get_contents().unwrap();
7840 let input = EndianSlice::new(&input, LittleEndian);
7841 let mut rest = input;
7842
7843 let parameters = PointerEncodingParameters {
7844 bases: &SectionBaseAddresses::default(),
7845 func_base: None,
7846 address_size: 4,
7847 section: &input,
7848 };
7849 assert_eq!(
7850 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7851 Err(Error::CannotParseOmitPointerEncoding)
7852 );
7853 assert_eq!(rest, input);
7854 }
7855
7856 #[test]
7857 fn test_parse_encoded_pointer_bad_encoding() {
7858 let encoding = constants::DwEhPe(constants::DW_EH_PE_sdata8.0 + 1);
7859
7860 let input = Section::with_endian(Endian::Little).L32(0x1);
7861 let input = input.get_contents().unwrap();
7862 let input = EndianSlice::new(&input, LittleEndian);
7863 let mut rest = input;
7864
7865 let parameters = PointerEncodingParameters {
7866 bases: &SectionBaseAddresses::default(),
7867 func_base: None,
7868 address_size: 4,
7869 section: &input,
7870 };
7871 assert_eq!(
7872 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7873 Err(Error::UnknownPointerEncoding(encoding))
7874 );
7875 }
7876
7877 #[test]
7878 fn test_parse_encoded_pointer_aligned() {
7879 let encoding = constants::DW_EH_PE_aligned;
7882
7883 let input = Section::with_endian(Endian::Little).L32(0x1);
7884 let input = input.get_contents().unwrap();
7885 let input = EndianSlice::new(&input, LittleEndian);
7886 let mut rest = input;
7887
7888 let parameters = PointerEncodingParameters {
7889 bases: &SectionBaseAddresses::default(),
7890 func_base: None,
7891 address_size: 4,
7892 section: &input,
7893 };
7894 assert_eq!(
7895 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7896 Err(Error::UnsupportedPointerEncoding)
7897 );
7898 }
7899
7900 #[test]
7901 fn test_parse_encoded_pointer_indirect() {
7902 let expected_rest = [1, 2, 3, 4];
7903 let encoding = constants::DW_EH_PE_indirect;
7904
7905 let input = Section::with_endian(Endian::Little)
7906 .L32(0x1234_5678)
7907 .append_bytes(&expected_rest);
7908 let input = input.get_contents().unwrap();
7909 let input = EndianSlice::new(&input, LittleEndian);
7910 let mut rest = input;
7911
7912 let parameters = PointerEncodingParameters {
7913 bases: &SectionBaseAddresses::default(),
7914 func_base: None,
7915 address_size: 4,
7916 section: &input,
7917 };
7918 assert_eq!(
7919 parse_encoded_pointer(encoding, ¶meters, &mut rest),
7920 Ok(Pointer::Indirect(0x1234_5678))
7921 );
7922 assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));
7923 }
7924
7925 #[test]
7926 fn test_unwind_context_reuse() {
7927 fn unwind_one(ctx: &mut UnwindContext<usize>, data: &[u8]) {
7928 let debug_frame = DebugFrame::new(data, NativeEndian);
7929 let bases = Default::default();
7930 let result = debug_frame.unwind_info_for_address(
7931 &bases,
7932 ctx,
7933 0xbadb_ad99,
7934 DebugFrame::cie_from_offset,
7935 );
7936 assert!(result.is_err());
7937 assert_eq!(result.unwrap_err(), Error::NoUnwindInfoForAddress);
7938 }
7939
7940 let mut ctx: UnwindContext<usize> = UnwindContext::new();
7942 {
7943 let data1 = vec![];
7944 unwind_one(&mut ctx, &data1);
7945 }
7946 {
7947 let data2 = vec![];
7948 unwind_one(&mut ctx, &data2);
7949 }
7950 }
7951}