1use bitflags::bitflags;
9use core::fmt::Write;
10use fallible_iterator::FallibleIterator;
11use std::cmp::Ordering;
12use thiserror::Error;
13
14macro_rules! read_binary {
15 ($data: expr, $le: expr, $ty: ident, $offset: expr) => {{
16 let data_offset = $offset;
17 let mut data_bytes: [u8; core::mem::size_of::<$ty>()] = [0; core::mem::size_of::<$ty>()];
18 data_bytes.copy_from_slice(&$data[data_offset..data_offset + core::mem::size_of::<$ty>()]);
19 if $le {
20 $ty::from_le_bytes(data_bytes)
21 } else {
22 $ty::from_be_bytes(data_bytes)
23 }
24 }};
25}
26
27macro_rules! read_struct {
28 ($struct: ident, $data: expr, $le: expr, $x: ident, $ty: ident) => {{ read_binary!($data, $le, $ty, core::mem::offset_of!($struct, $x)) }};
29}
30
31pub type SFrameResult<T> = core::result::Result<T, SFrameError>;
33
34#[derive(Debug, Clone, Copy)]
38pub enum SFrameVersion {
39 V1,
41 V2,
43}
44
45#[derive(Debug, Clone, Copy)]
49pub enum SFrameABI {
50 AArch64BigEndian,
52 AArch64LittleEndian,
54 AMD64LittleEndian,
56 S390XBigEndian,
58}
59
60bitflags! {
61 #[derive(Debug, Clone, Copy)]
65 pub struct SFrameFlags: u8 {
66 const SFRAME_F_FDE_SORTED = 0x1;
68 const SFRAME_F_FRAME_POINTER = 0x2;
70 const SFRAME_F_FDE_FUNC_START_PCREL = 0x4;
72 }
73}
74
75#[derive(Debug, Clone, Copy)]
79#[allow(dead_code)]
80pub struct SFrameSection<'a> {
81 data: &'a [u8],
82 section_base: u64,
83 little_endian: bool,
84 version: SFrameVersion,
85 flags: SFrameFlags,
86 abi: SFrameABI,
87 cfa_fixed_fp_offset: i8,
88 cfa_fixed_ra_offset: i8,
89 auxhdr_len: u8,
90 num_fdes: u32,
91 num_fres: u32,
92 fre_len: u32,
93 fdeoff: u32,
94 freoff: u32,
95}
96
97const SFRAME_MAGIC: u16 = 0xdee2;
99
100impl<'a> SFrameSection<'a> {
101 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
103 if data.len() < core::mem::size_of::<RawSFrameHeader>() {
105 return Err(SFrameError::UnexpectedEndOfData);
106 }
107
108 let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
110 let mut magic_bytes: [u8; 2] = [0; 2];
111 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
112 let magic_le = u16::from_le_bytes(magic_bytes);
113 let little_endian;
114 if magic_le == SFRAME_MAGIC {
115 little_endian = true;
116 } else {
117 let magic_be = u16::from_be_bytes(magic_bytes);
118 if magic_be == SFRAME_MAGIC {
119 little_endian = false;
120 } else {
121 return Err(SFrameError::InvalidMagic);
122 }
123 }
124
125 let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
127 let version = data[version_offset];
128 let version = match version {
129 1 => SFrameVersion::V1,
130 2 => SFrameVersion::V2,
131 _ => return Err(SFrameError::UnsupportedVersion),
132 };
133
134 let flags_offset = core::mem::offset_of!(RawSFrameHeader, flags);
136 let flags = data[flags_offset];
137 let flags = match SFrameFlags::from_bits(flags) {
138 Some(flags) => flags,
139 None => return Err(SFrameError::UnsupportedFlags),
140 };
141
142 let abi_offset = core::mem::offset_of!(RawSFrameHeader, abi_arch);
144 let abi = data[abi_offset];
145 let abi = match abi {
146 1 => SFrameABI::AArch64BigEndian,
147 2 => SFrameABI::AArch64LittleEndian,
148 3 => SFrameABI::AMD64LittleEndian,
149 4 => SFrameABI::S390XBigEndian,
150 _ => return Err(SFrameError::UnsupportedABI),
151 };
152
153 let cfa_fixed_fp_offset =
154 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_fp_offset)] as i8;
155 let cfa_fixed_ra_offset =
156 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_ra_offset)] as i8;
157 let auxhdr_len = data[core::mem::offset_of!(RawSFrameHeader, auxhdr_len)];
158
159 Ok(SFrameSection {
160 data,
161 section_base,
162 little_endian,
163 version,
164 flags,
165 abi,
166 cfa_fixed_fp_offset,
167 cfa_fixed_ra_offset,
168 auxhdr_len,
169 num_fdes: read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32),
170 num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
171 fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
172 fdeoff: read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32),
173 freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
174 })
175 }
176
177 pub fn get_fde_count(&self) -> u32 {
179 self.num_fdes
180 }
181
182 pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
184 if index >= self.num_fdes {
185 return Ok(None);
187 }
188
189 let offset = self.fdeoff as usize
194 + index as usize * core::mem::size_of::<RawSFrameFDE>()
195 + core::mem::size_of::<RawSFrameHeader>();
196 if offset + core::mem::size_of::<RawSFrameFDE>() > self.data.len() {
197 return Err(SFrameError::UnexpectedEndOfData);
198 }
199
200 Ok(Some(SFrameFDE {
201 offset,
202 func_start_address: read_struct!(
203 RawSFrameFDE,
204 &self.data[offset..],
205 self.little_endian,
206 func_start_address,
207 i32
208 ),
209 func_size: read_struct!(
210 RawSFrameFDE,
211 &self.data[offset..],
212 self.little_endian,
213 func_size,
214 u32
215 ),
216 func_start_fre_off: read_struct!(
217 RawSFrameFDE,
218 &self.data[offset..],
219 self.little_endian,
220 func_start_fre_off,
221 u32
222 ),
223 func_num_fres: read_struct!(
224 RawSFrameFDE,
225 &self.data[offset..],
226 self.little_endian,
227 func_num_fres,
228 u32
229 ),
230 func_info: SFrameFDEInfo(
231 self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_info)],
232 ),
233 func_rep_size: self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_rep_size)],
234 }))
235 }
236
237 pub fn to_string(&self) -> SFrameResult<String> {
239 let mut s = String::new();
240 writeln!(&mut s, "Header :")?;
241 writeln!(&mut s)?;
242 writeln!(
243 &mut s,
244 " Version: {}",
245 match self.version {
246 SFrameVersion::V1 => "SFRAME_VERSION_1",
247 SFrameVersion::V2 => "SFRAME_VERSION_2",
248 }
249 )?;
250 writeln!(
251 &mut s,
252 " Flags: {}",
253 self.flags
254 .iter_names()
255 .map(|(name, _flag)| name)
256 .collect::<Vec<_>>()
257 .join(" | ")
258 )?;
259 if self.cfa_fixed_fp_offset != 0 {
260 writeln!(
261 &mut s,
262 " CFA fixed FP offset: {:?}",
263 self.cfa_fixed_fp_offset
264 )?;
265 }
266 if self.cfa_fixed_ra_offset != 0 {
267 writeln!(
268 &mut s,
269 " CFA fixed RA offset: {:?}",
270 self.cfa_fixed_ra_offset
271 )?;
272 }
273 writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
274 writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
275 writeln!(&mut s)?;
276 writeln!(&mut s, "Function Index :")?;
277 writeln!(&mut s)?;
278 for i in 0..self.num_fdes {
279 let fde = self.get_fde(i)?.unwrap();
280 let pc = fde.get_pc(self);
281 writeln!(
282 &mut s,
283 " func idx [{i}]: pc = 0x{:x}, size = {} bytes",
284 pc, fde.func_size,
285 )?;
286
287 match fde.func_info.get_fde_type()? {
288 SFrameFDEType::PCInc => {
289 writeln!(&mut s, " STARTPC CFA FP RA")?;
290 }
291 SFrameFDEType::PCMask => {
292 writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
293 }
294 }
295 let mut iter = fde.iter_fre(self);
296 while let Some(fre) = iter.next()? {
297 let start_pc = match fde.func_info.get_fde_type()? {
298 SFrameFDEType::PCInc => pc + fre.start_address.get() as u64,
299 SFrameFDEType::PCMask => fre.start_address.get() as u64,
300 };
301 let rest = match self.abi {
302 SFrameABI::AMD64LittleEndian => {
303 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
305 "fp"
306 } else {
307 "sp"
308 };
309 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
310 let fp = match fre.stack_offsets.get(1) {
311 Some(offset) => format!("c{:+}", offset.get()),
312 None => "u".to_string(), };
314 let ra = "f"; format!("{cfa:8} {fp:6} {ra}")
316 }
317 SFrameABI::AArch64LittleEndian => {
318 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
320 "fp"
321 } else {
322 "sp"
323 };
324 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
325 let fp = match fre.stack_offsets.get(1) {
326 Some(offset) => format!("c{:+}", offset.get()),
327 None => "u".to_string(), };
329 let ra = match fre.stack_offsets.get(2) {
330 Some(offset) => format!("c{:+}", offset.get()),
331 None => "u".to_string(), };
333 format!("{cfa:8} {fp:6} {ra}")
334 }
335 _ => todo!(),
336 };
337 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
338 }
339 writeln!(&mut s,)?;
340 }
341 Ok(s)
342 }
343
344 pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
346 SFrameFDEIterator {
347 section: self,
348 index: 0,
349 }
350 }
351
352 pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
354 if self.flags.contains(SFrameFlags::SFRAME_F_FDE_SORTED) {
355 let mut size = self.num_fdes;
358 if size == 0 {
359 return Ok(None);
360 }
361 let mut base = 0;
362
363 while size > 1 {
364 let half = size / 2;
365 let mid = base + half;
366
367 let cmp = self.get_fde(mid)?.unwrap().get_pc(self).cmp(&pc);
368 if cmp != Ordering::Greater {
369 base = mid;
370 }
371 size -= half;
372 }
373
374 let base_fde = self.get_fde(base)?.unwrap();
375 let base_pc = base_fde.get_pc(self);
376 let cmp = base_pc.cmp(&pc);
377 match cmp {
378 Ordering::Equal | Ordering::Less if pc < base_pc + base_fde.func_size as u64 => {
379 Ok(Some(base_fde))
380 }
381 _ => Ok(None),
382 }
383 } else {
384 let mut iter = self.iter_fde();
386 while let Some(fde) = iter.next()? {
387 let start = fde.get_pc(self);
388 let end = start + fde.func_size as u64;
389 if start <= pc && pc < end {
390 return Ok(Some(fde));
391 }
392 }
393 Ok(None)
394 }
395 }
396
397 pub fn get_version(&self) -> SFrameVersion {
399 self.version
400 }
401
402 pub fn get_flags(&self) -> SFrameFlags {
404 self.flags
405 }
406
407 pub fn get_abi(&self) -> SFrameABI {
409 self.abi
410 }
411
412 pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
414 self.cfa_fixed_fp_offset
415 }
416
417 pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
419 self.cfa_fixed_ra_offset
420 }
421}
422
423#[repr(C, packed)]
427struct RawSFrameHeader {
428 magic: u16,
429 version: u8,
430 flags: u8,
431 abi_arch: u8,
432 cfa_fixed_fp_offset: i8,
433 cfa_fixed_ra_offset: i8,
434 auxhdr_len: u8,
435 num_fdes: u32,
436 num_fres: u32,
437 fre_len: u32,
438 fdeoff: u32,
439 freoff: u32,
440}
441
442#[repr(C, packed)]
446#[allow(dead_code)]
447struct RawSFrameFDE {
448 func_start_address: i32,
449 func_size: u32,
450 func_start_fre_off: u32,
451 func_num_fres: u32,
452 func_info: u8,
453 func_rep_size: u8,
454 func_padding2: u16,
455}
456
457#[derive(Debug, Clone, Copy)]
461#[repr(transparent)]
462pub struct SFrameFDEInfo(u8);
463
464impl SFrameFDEInfo {
465 pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
467 let fretype = self.0 & 0b1111;
468 match fretype {
469 0 => Ok(SFrameFREType::Addr0),
470 1 => Ok(SFrameFREType::Addr1),
471 2 => Ok(SFrameFREType::Addr2),
472 _ => Err(SFrameError::UnsupportedFREType),
473 }
474 }
475
476 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
478 let fretype = (self.0 >> 4) & 0b1;
479 match fretype {
480 0 => Ok(SFrameFDEType::PCInc),
481 1 => Ok(SFrameFDEType::PCMask),
482 _ => unreachable!(),
483 }
484 }
485
486 pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
488 let fretype = (self.0 >> 5) & 0b1;
489 match fretype {
490 0 => Ok(SFrameAArch64PAuthKey::KeyA),
491 1 => Ok(SFrameAArch64PAuthKey::KeyB),
492 _ => unreachable!(),
493 }
494 }
495}
496
497#[derive(Debug, Clone, Copy)]
501pub enum SFrameFREType {
502 Addr0,
506 Addr1,
510 Addr2,
514}
515
516#[derive(Debug, Clone, Copy)]
520pub enum SFrameFDEType {
521 PCInc,
523 PCMask,
525}
526
527#[derive(Debug, Clone, Copy)]
531pub enum SFrameAArch64PAuthKey {
532 KeyA,
534 KeyB,
536}
537
538#[derive(Debug, Clone, Copy)]
542pub struct SFrameFDE {
543 offset: usize,
545 pub func_start_address: i32,
552 pub func_size: u32,
555 pub func_start_fre_off: u32,
558 pub func_num_fres: u32,
561 pub func_info: SFrameFDEInfo,
564 pub func_rep_size: u8,
568}
569
570impl SFrameFDE {
571 pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
573 if section
579 .flags
580 .contains(SFrameFlags::SFRAME_F_FDE_FUNC_START_PCREL)
581 {
582 (self.func_start_address as i64 + self.offset as i64 + section.section_base as i64)
583 as u64
584 } else {
585 (self.func_start_address as i64 + section.section_base as i64) as u64
586 }
587 }
588
589 pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
591 let offset = section.freoff as usize
600 + core::mem::size_of::<RawSFrameHeader>()
601 + self.func_start_fre_off as usize;
602 SFrameFREIterator {
603 fde: self,
604 section,
605 offset,
606 index: 0,
607 }
608 }
609
610 pub fn find_fre(
612 &self,
613 section: &SFrameSection<'_>,
614 pc: u64,
615 ) -> SFrameResult<Option<SFrameFRE>> {
616 let fde_pc = self.get_pc(section);
617 match self.func_info.get_fde_type()? {
618 SFrameFDEType::PCInc => {
619 let mut last: Option<SFrameFRE> = None;
621 let mut iter = self.iter_fre(§ion);
622 while let Some(fre) = iter.next()? {
623 if fre.start_address.get() as u64 + fde_pc > pc {
624 break;
626 }
627 last = Some(fre);
628 }
629 if let Some(fre) = last {
630 if fre.start_address.get() as u64 + fde_pc <= pc {
632 return Ok(Some(fre));
633 }
634 }
635 return Ok(None);
636 }
637 SFrameFDEType::PCMask => {
638 let mut iter = self.iter_fre(§ion);
640 while let Some(fre) = iter.next()? {
641 if pc % self.func_rep_size as u64 >= fre.start_address.get() as u64 {
643 return Ok(Some(fre));
645 }
646 }
647 return Ok(None);
648 }
649 }
650 }
651}
652
653#[derive(Debug, Clone, Copy)]
657pub enum SFrameFREStartAddress {
658 U8(u8),
659 U16(u16),
660 U32(u32),
661}
662
663impl SFrameFREStartAddress {
664 pub fn get(&self) -> u32 {
666 match self {
667 SFrameFREStartAddress::U8(i) => *i as u32,
668 SFrameFREStartAddress::U16(i) => *i as u32,
669 SFrameFREStartAddress::U32(i) => *i,
670 }
671 }
672}
673
674#[derive(Debug, Clone, Copy)]
678pub enum SFrameFREStackOffset {
679 I8(i8),
680 I16(i16),
681 I32(i32),
682}
683
684impl SFrameFREStackOffset {
685 pub fn get(&self) -> i32 {
687 match self {
688 SFrameFREStackOffset::I8(i) => *i as i32,
689 SFrameFREStackOffset::I16(i) => *i as i32,
690 SFrameFREStackOffset::I32(i) => *i,
691 }
692 }
693}
694
695#[derive(Debug, Clone)]
699pub struct SFrameFRE {
700 pub start_address: SFrameFREStartAddress,
702 pub info: SFrameFREInfo,
704 pub stack_offsets: Vec<SFrameFREStackOffset>,
706}
707
708impl SFrameFRE {
709 pub fn get_cfa_offset(&self) -> Option<i32> {
711 self.stack_offsets.get(0).map(|offset| offset.get())
713 }
714
715 pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
717 match section.abi {
718 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
720 self.stack_offsets.get(1).map(|offset| offset.get())
721 }
722 SFrameABI::AMD64LittleEndian => Some(section.cfa_fixed_ra_offset as i32),
724 SFrameABI::S390XBigEndian => todo!(),
726 }
727 }
728
729 pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
731 match section.abi {
732 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
734 self.stack_offsets.get(2).map(|offset| offset.get())
735 }
736 SFrameABI::AMD64LittleEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
738 SFrameABI::S390XBigEndian => todo!(),
740 }
741 }
742}
743
744#[derive(Debug, Clone, Copy)]
748#[repr(transparent)]
749pub struct SFrameFREInfo(u8);
750
751impl SFrameFREInfo {
752 pub fn get_mangled_ra_p(&self) -> bool {
755 (self.0 >> 7) & 0b1 == 1
756 }
757
758 pub fn get_offset_size(&self) -> SFrameResult<usize> {
760 match (self.0 >> 5) & 0b11 {
761 0x0 => Ok(1),
763 0x1 => Ok(2),
765 0x2 => Ok(4),
767 _ => Err(SFrameError::UnsupportedFREStackOffsetSize),
768 }
769 }
770
771 pub fn get_offset_count(&self) -> u8 {
773 (self.0 >> 1) & 0b111
774 }
775
776 pub fn get_cfa_base_reg_id(&self) -> u8 {
778 self.0 & 0b1
779 }
780}
781
782pub struct SFrameFREIterator<'a> {
784 fde: &'a SFrameFDE,
785 section: &'a SFrameSection<'a>,
786 index: u32,
787 offset: usize,
788}
789
790impl<'a> FallibleIterator for SFrameFREIterator<'a> {
791 type Item = SFrameFRE;
792 type Error = SFrameError;
793
794 fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
795 if self.index >= self.fde.func_num_fres {
796 return Ok(None);
797 }
798
799 let fre_type = self.fde.func_info.get_fre_type()?;
800 let entry_size = match fre_type {
801 SFrameFREType::Addr0 => 1 + 1,
802 SFrameFREType::Addr1 => 2 + 1,
803 SFrameFREType::Addr2 => 4 + 1,
804 } as usize;
805 let offset = self.offset;
806 if offset + entry_size > self.section.data.len() {
807 return Err(SFrameError::UnexpectedEndOfData);
808 }
809
810 let (start_address, info) = match self.fde.func_info.get_fre_type()? {
811 SFrameFREType::Addr0 => (
812 SFrameFREStartAddress::U8(self.section.data[offset]),
813 SFrameFREInfo(self.section.data[offset + 1]),
814 ),
815 SFrameFREType::Addr1 => (
816 SFrameFREStartAddress::U16(read_binary!(
817 self.section.data,
818 self.section.little_endian,
819 u16,
820 offset
821 )),
822 SFrameFREInfo(self.section.data[offset + 2]),
823 ),
824 SFrameFREType::Addr2 => (
825 SFrameFREStartAddress::U32(read_binary!(
826 self.section.data,
827 self.section.little_endian,
828 u32,
829 offset
830 )),
831 SFrameFREInfo(self.section.data[offset + 4]),
832 ),
833 };
834
835 let offset_size = info.get_offset_size()?;
836 let offset_count = info.get_offset_count() as usize;
837 let offset_total_size = offset_size * offset_count;
838 if offset + entry_size + offset_total_size > self.section.data.len() {
839 return Err(SFrameError::UnexpectedEndOfData);
840 }
841
842 let mut stack_offsets = vec![];
843 for i in 0..offset_count {
844 match offset_size {
845 1 => stack_offsets.push(SFrameFREStackOffset::I8(
846 self.section.data[offset + entry_size + i * offset_size] as i8,
847 )),
848 2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
849 self.section.data,
850 self.section.little_endian,
851 i16,
852 offset + entry_size + i * offset_size
853 ))),
854 4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
855 self.section.data,
856 self.section.little_endian,
857 i32,
858 offset + entry_size + i * offset_size
859 ))),
860 _ => unreachable!(),
861 }
862 }
863
864 self.offset += entry_size + offset_total_size;
865 self.index += 1;
866
867 Ok(Some(SFrameFRE {
868 start_address,
869 info,
870 stack_offsets,
871 }))
872 }
873}
874
875pub struct SFrameFDEIterator<'a> {
877 section: &'a SFrameSection<'a>,
878 index: u32,
879}
880
881impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
882 type Item = SFrameFDE;
883 type Error = SFrameError;
884
885 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
886 let res = self.section.get_fde(self.index);
887 if let Ok(Some(_)) = res {
888 self.index += 1;
889 }
890 res
891 }
892}
893
894#[derive(Error, Debug)]
896pub enum SFrameError {
897 #[error("format error")]
899 Fmt(#[from] core::fmt::Error),
900 #[error("unexpected end of data")]
902 UnexpectedEndOfData,
903 #[error("invalid magic number")]
905 InvalidMagic,
906 #[error("unsupported version")]
908 UnsupportedVersion,
909 #[error("unsupported flags")]
911 UnsupportedFlags,
912 #[error("unsupported abi")]
914 UnsupportedABI,
915 #[error("unsupported fre type")]
917 UnsupportedFREType,
918 #[error("unsupported fre stack offset size")]
920 UnsupportedFREStackOffsetSize,
921}
922
923#[cfg(test)]
924mod tests {
925 use std::iter::zip;
926
927 use serde::{Deserialize, Serialize};
928 #[derive(Serialize, Deserialize)]
929 struct Testcase {
930 section_base: u64,
931 content: Vec<u8>,
932 groundtruth: String,
933 }
934
935 #[test]
936 fn test() {
937 for entry in std::fs::read_dir("testcases").unwrap() {
938 let entry = entry.unwrap();
939 let testcase: Testcase =
940 serde_json::from_reader(std::fs::File::open(entry.path()).unwrap()).unwrap();
941 let section =
942 crate::SFrameSection::from(&testcase.content, testcase.section_base).unwrap();
943 let s = section.to_string().unwrap();
944 let mut lines_expected: Vec<&str> = testcase.groundtruth.trim().split("\n").collect();
945
946 while let Some(line) = lines_expected.first() {
948 if line.contains("Header :") {
949 break;
950 }
951 lines_expected.remove(0);
952 }
953 let lines_actual: Vec<&str> = s.trim().split("\n").collect();
954
955 assert_eq!(lines_expected.len(), lines_actual.len());
957 for (expected, actual) in zip(lines_expected, lines_actual) {
958 let parts_expected: Vec<&str> =
959 expected.trim().split(" ").filter(|s| s.len() > 0).collect();
960 let parts_actual: Vec<&str> =
961 actual.trim().split(" ").filter(|s| s.len() > 0).collect();
962 assert_eq!(
963 parts_expected, parts_actual,
964 "\"{}\"({:?}) != \"{}\"({:?})",
965 expected, parts_expected, actual, parts_actual,
966 );
967 }
968 }
969 }
970}