1use bitflags::bitflags;
9use core::fmt::Write;
10use fallible_iterator::FallibleIterator;
11use thiserror::Error;
12
13macro_rules! read_binary {
14 ($data: expr, $le: expr, $ty: ident, $offset: expr) => {{
15 let data_offset = $offset;
16 let mut data_bytes: [u8; core::mem::size_of::<$ty>()] = [0; core::mem::size_of::<$ty>()];
17 data_bytes.copy_from_slice(&$data[data_offset..data_offset + core::mem::size_of::<$ty>()]);
18 if $le {
19 $ty::from_le_bytes(data_bytes)
20 } else {
21 $ty::from_be_bytes(data_bytes)
22 }
23 }};
24}
25
26macro_rules! read_struct {
27 ($struct: ident, $data: expr, $le: expr, $x: ident, $ty: ident) => {{ read_binary!($data, $le, $ty, core::mem::offset_of!($struct, $x)) }};
28}
29
30pub type SFrameResult<T> = core::result::Result<T, SFrameError>;
32
33#[derive(Debug, Clone, Copy)]
37pub enum SFrameVersion {
38 V1,
40 V2,
42}
43
44#[derive(Debug, Clone, Copy)]
48pub enum SFrameABI {
49 AArch64BigEndian,
51 AArch64LittleEndian,
53 AMD64LittleEndian,
55 S390XBigEndian,
57}
58
59bitflags! {
60 #[derive(Debug, Clone, Copy)]
64 pub struct SFrameFlags: u8 {
65 const SFRAME_F_FDE_SORTED = 0x1;
67 const SFRAME_F_FRAME_POINTER = 0x2;
69 const SFRAME_F_FDE_FUNC_START_PCREL = 0x4;
71 }
72}
73
74#[derive(Debug, Clone, Copy)]
78#[allow(dead_code)]
79pub struct SFrameSection<'a> {
80 data: &'a [u8],
81 section_base: u64,
82 little_endian: bool,
83 version: SFrameVersion,
84 flags: SFrameFlags,
85 abi: SFrameABI,
86 cfa_fixed_fp_offset: i8,
87 cfa_fixed_ra_offset: i8,
88 auxhdr_len: u8,
89 num_fdes: u32,
90 num_fres: u32,
91 fre_len: u32,
92 fdeoff: u32,
93 freoff: u32,
94}
95
96#[repr(C, packed)]
100struct RawSFrameHeader {
101 magic: u16,
102 version: u8,
103 flags: u8,
104 abi_arch: u8,
105 cfa_fixed_fp_offset: i8,
106 cfa_fixed_ra_offset: i8,
107 auxhdr_len: u8,
108 num_fdes: u32,
109 num_fres: u32,
110 fre_len: u32,
111 fdeoff: u32,
112 freoff: u32,
113}
114
115#[repr(C, packed)]
119#[allow(dead_code)]
120struct RawSFrameFDE {
121 func_start_address: i32,
122 func_size: u32,
123 func_start_fre_off: u32,
124 func_num_fres: u32,
125 func_info: u8,
126 func_rep_size: u8,
127 func_padding2: u16,
128}
129
130#[derive(Debug, Clone, Copy)]
134#[repr(transparent)]
135pub struct SFrameFDEInfo(u8);
136
137impl SFrameFDEInfo {
138 pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
140 let fretype = self.0 & 0b1111;
141 match fretype {
142 0 => Ok(SFrameFREType::Addr0),
143 1 => Ok(SFrameFREType::Addr1),
144 2 => Ok(SFrameFREType::Addr2),
145 _ => Err(SFrameError::UnsupportedFREType),
146 }
147 }
148
149 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
151 let fretype = (self.0 >> 4) & 0b1;
152 match fretype {
153 0 => Ok(SFrameFDEType::PCInc),
154 1 => Ok(SFrameFDEType::PCMask),
155 _ => unreachable!(),
156 }
157 }
158
159 pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
161 let fretype = (self.0 >> 5) & 0b1;
162 match fretype {
163 0 => Ok(SFrameAArch64PAuthKey::KeyA),
164 1 => Ok(SFrameAArch64PAuthKey::KeyB),
165 _ => unreachable!(),
166 }
167 }
168}
169
170#[derive(Debug, Clone, Copy)]
174pub enum SFrameFREType {
175 Addr0,
179 Addr1,
183 Addr2,
187}
188
189#[derive(Debug, Clone, Copy)]
193pub enum SFrameFDEType {
194 PCInc,
196 PCMask,
198}
199
200#[derive(Debug, Clone, Copy)]
204pub enum SFrameAArch64PAuthKey {
205 KeyA,
207 KeyB,
209}
210
211#[derive(Debug, Clone, Copy)]
215pub struct SFrameFDE {
216 offset: usize,
218 pub func_start_address: i32,
225 pub func_size: u32,
228 pub func_start_fre_off: u32,
231 pub func_num_fres: u32,
234 pub func_info: SFrameFDEInfo,
237 pub func_rep_size: u8,
241}
242
243#[derive(Debug, Clone, Copy)]
247pub enum SFrameFREStartAddress {
248 U8(u8),
249 U16(u16),
250 U32(u32),
251}
252
253impl SFrameFREStartAddress {
254 pub fn get(&self) -> u32 {
256 match self {
257 SFrameFREStartAddress::U8(i) => *i as u32,
258 SFrameFREStartAddress::U16(i) => *i as u32,
259 SFrameFREStartAddress::U32(i) => *i,
260 }
261 }
262}
263
264#[derive(Debug, Clone, Copy)]
268pub enum SFrameFREStackOffset {
269 I8(i8),
270 I16(i16),
271 I32(i32),
272}
273
274impl SFrameFREStackOffset {
275 pub fn get(&self) -> i32 {
277 match self {
278 SFrameFREStackOffset::I8(i) => *i as i32,
279 SFrameFREStackOffset::I16(i) => *i as i32,
280 SFrameFREStackOffset::I32(i) => *i,
281 }
282 }
283}
284
285#[derive(Debug, Clone)]
289pub struct SFrameFRE {
290 pub start_address: SFrameFREStartAddress,
292 pub info: SFrameFREInfo,
294 pub stack_offsets: Vec<SFrameFREStackOffset>,
296}
297
298#[derive(Debug, Clone, Copy)]
302#[repr(transparent)]
303pub struct SFrameFREInfo(u8);
304
305impl SFrameFREInfo {
306 pub fn get_mangled_ra_p(&self) -> bool {
309 (self.0 >> 7) & 0b1 == 1
310 }
311
312 pub fn get_offset_size(&self) -> SFrameResult<usize> {
314 match (self.0 >> 5) & 0b11 {
315 0x0 => Ok(1),
317 0x1 => Ok(2),
319 0x2 => Ok(4),
321 _ => Err(SFrameError::UnsupportedFREStackOffsetSize),
322 }
323 }
324
325 pub fn get_offset_count(&self) -> u8 {
327 (self.0 >> 1) & 0b111
328 }
329
330 pub fn get_cfa_base_reg_id(&self) -> u8 {
332 self.0 & 0b1
333 }
334}
335
336pub struct SFrameFREIterator<'a> {
338 fde: &'a SFrameFDE,
339 section: &'a SFrameSection<'a>,
340 index: u32,
341 offset: usize,
342}
343
344impl<'a> FallibleIterator for SFrameFREIterator<'a> {
345 type Item = SFrameFRE;
346 type Error = SFrameError;
347
348 fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
349 if self.index >= self.fde.func_num_fres {
350 return Ok(None);
351 }
352
353 let fre_type = self.fde.func_info.get_fre_type()?;
354 let entry_size = match fre_type {
355 SFrameFREType::Addr0 => 1 + 1,
356 SFrameFREType::Addr1 => 2 + 1,
357 SFrameFREType::Addr2 => 4 + 1,
358 } as usize;
359 let offset = self.offset;
360 if offset + entry_size > self.section.data.len() {
361 return Err(SFrameError::UnexpectedEndOfData);
362 }
363
364 let (start_address, info) = match self.fde.func_info.get_fre_type()? {
365 SFrameFREType::Addr0 => (
366 SFrameFREStartAddress::U8(self.section.data[offset]),
367 SFrameFREInfo(self.section.data[offset + 1]),
368 ),
369 SFrameFREType::Addr1 => (
370 SFrameFREStartAddress::U16(read_binary!(
371 self.section.data,
372 self.section.little_endian,
373 u16,
374 offset
375 )),
376 SFrameFREInfo(self.section.data[offset + 2]),
377 ),
378 SFrameFREType::Addr2 => (
379 SFrameFREStartAddress::U32(read_binary!(
380 self.section.data,
381 self.section.little_endian,
382 u32,
383 offset
384 )),
385 SFrameFREInfo(self.section.data[offset + 4]),
386 ),
387 };
388
389 let offset_size = info.get_offset_size()?;
390 let offset_count = info.get_offset_count() as usize;
391 let offset_total_size = offset_size * offset_count;
392 if offset + entry_size + offset_total_size > self.section.data.len() {
393 return Err(SFrameError::UnexpectedEndOfData);
394 }
395
396 let mut stack_offsets = vec![];
397 for i in 0..offset_count {
398 match offset_size {
399 1 => stack_offsets.push(SFrameFREStackOffset::I8(
400 self.section.data[offset + entry_size + i * offset_size] as i8,
401 )),
402 2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
403 self.section.data,
404 self.section.little_endian,
405 i16,
406 offset + entry_size + i * offset_size
407 ))),
408 4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
409 self.section.data,
410 self.section.little_endian,
411 i32,
412 offset + entry_size + i * offset_size
413 ))),
414 _ => unreachable!(),
415 }
416 }
417
418 self.offset += entry_size + offset_total_size;
419 self.index += 1;
420
421 Ok(Some(SFrameFRE {
422 start_address,
423 info,
424 stack_offsets,
425 }))
426 }
427}
428
429impl SFrameFDE {
430 pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
432 if section
433 .flags
434 .contains(SFrameFlags::SFRAME_F_FDE_FUNC_START_PCREL)
435 {
436 (self.func_start_address as i64 + self.offset as i64 + section.section_base as i64)
437 as u64
438 } else {
439 (self.func_start_address as i64 + section.section_base as i64) as u64
440 }
441 }
442
443 pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
444 let offset = section.freoff as usize
445 + core::mem::size_of::<RawSFrameHeader>()
446 + self.func_start_fre_off as usize;
447 SFrameFREIterator {
448 fde: self,
449 section,
450 offset,
451 index: 0,
452 }
453 }
454}
455
456const SFRAME_MAGIC: u16 = 0xdee2;
458
459impl<'a> SFrameSection<'a> {
460 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
462 if data.len() < core::mem::size_of::<RawSFrameHeader>() {
464 return Err(SFrameError::UnexpectedEndOfData);
465 }
466
467 let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
469 let mut magic_bytes: [u8; 2] = [0; 2];
470 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
471 let magic_le = u16::from_le_bytes(magic_bytes);
472 let little_endian;
473 if magic_le == SFRAME_MAGIC {
474 little_endian = true;
475 } else {
476 let magic_be = u16::from_be_bytes(magic_bytes);
477 if magic_be == SFRAME_MAGIC {
478 little_endian = false;
479 } else {
480 return Err(SFrameError::InvalidMagic);
481 }
482 }
483
484 let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
486 let version = data[version_offset];
487 let version = match version {
488 1 => SFrameVersion::V1,
489 2 => SFrameVersion::V2,
490 _ => return Err(SFrameError::UnsupportedVersion),
491 };
492
493 let flags_offset = core::mem::offset_of!(RawSFrameHeader, flags);
495 let flags = data[flags_offset];
496 let flags = match SFrameFlags::from_bits(flags) {
497 Some(flags) => flags,
498 None => return Err(SFrameError::UnsupportedFlags),
499 };
500
501 let abi_offset = core::mem::offset_of!(RawSFrameHeader, abi_arch);
503 let abi = data[abi_offset];
504 let abi = match abi {
505 1 => SFrameABI::AArch64BigEndian,
506 2 => SFrameABI::AArch64LittleEndian,
507 3 => SFrameABI::AMD64LittleEndian,
508 4 => SFrameABI::S390XBigEndian,
509 _ => return Err(SFrameError::UnsupportedABI),
510 };
511
512 let cfa_fixed_fp_offset =
513 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_fp_offset)] as i8;
514 let cfa_fixed_ra_offset =
515 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_ra_offset)] as i8;
516 let auxhdr_len = data[core::mem::offset_of!(RawSFrameHeader, auxhdr_len)];
517
518 Ok(SFrameSection {
519 data,
520 section_base,
521 little_endian,
522 version,
523 flags,
524 abi,
525 cfa_fixed_fp_offset,
526 cfa_fixed_ra_offset,
527 auxhdr_len,
528 num_fdes: read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32),
529 num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
530 fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
531 fdeoff: read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32),
532 freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
533 })
534 }
535
536 pub fn get_fde_count(&self) -> u32 {
538 self.num_fdes
539 }
540
541 pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
543 if index >= self.num_fdes {
544 return Ok(None);
546 }
547
548 let offset = self.fdeoff as usize
549 + index as usize * core::mem::size_of::<RawSFrameFDE>()
550 + core::mem::size_of::<RawSFrameHeader>();
551 if offset + core::mem::size_of::<RawSFrameFDE>() > self.data.len() {
552 return Err(SFrameError::UnexpectedEndOfData);
553 }
554
555 Ok(Some(SFrameFDE {
556 offset,
557 func_start_address: read_struct!(
558 RawSFrameFDE,
559 &self.data[offset..],
560 self.little_endian,
561 func_start_address,
562 i32
563 ),
564 func_size: read_struct!(
565 RawSFrameFDE,
566 &self.data[offset..],
567 self.little_endian,
568 func_size,
569 u32
570 ),
571 func_start_fre_off: read_struct!(
572 RawSFrameFDE,
573 &self.data[offset..],
574 self.little_endian,
575 func_start_fre_off,
576 u32
577 ),
578 func_num_fres: read_struct!(
579 RawSFrameFDE,
580 &self.data[offset..],
581 self.little_endian,
582 func_num_fres,
583 u32
584 ),
585 func_info: SFrameFDEInfo(
586 self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_info)],
587 ),
588 func_rep_size: self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_rep_size)],
589 }))
590 }
591
592 pub fn to_string(&self) -> SFrameResult<String> {
594 let mut s = String::new();
595 writeln!(&mut s, "Header :")?;
596 writeln!(&mut s)?;
597 writeln!(
598 &mut s,
599 " Version: {}",
600 match self.version {
601 SFrameVersion::V1 => "SFRAME_VERSION_1",
602 SFrameVersion::V2 => "SFRAME_VERSION_2",
603 }
604 )?;
605 writeln!(
606 &mut s,
607 " Flags: {}",
608 self.flags
609 .iter_names()
610 .map(|(name, _flag)| name)
611 .collect::<Vec<_>>()
612 .join(" | ")
613 )?;
614 if self.cfa_fixed_fp_offset != 0 {
615 writeln!(
616 &mut s,
617 " CFA fixed FP offset: {:?}",
618 self.cfa_fixed_fp_offset
619 )?;
620 }
621 if self.cfa_fixed_ra_offset != 0 {
622 writeln!(
623 &mut s,
624 " CFA fixed RA offset: {:?}",
625 self.cfa_fixed_ra_offset
626 )?;
627 }
628 writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
629 writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
630 writeln!(&mut s)?;
631 writeln!(&mut s, "Function Index :")?;
632 writeln!(&mut s)?;
633 for i in 0..self.num_fdes {
634 let fde = self.get_fde(i)?.unwrap();
635 let pc = fde.get_pc(self);
636 writeln!(
637 &mut s,
638 " func idx [{i}]: pc = 0x{:x}, size = {} bytes",
639 pc, fde.func_size,
640 )?;
641
642 match fde.func_info.get_fde_type()? {
643 SFrameFDEType::PCInc => {
644 writeln!(&mut s, " STARTPC CFA FP RA")?;
645 }
646 SFrameFDEType::PCMask => {
647 writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
648 }
649 }
650 let mut iter = fde.iter_fre(self);
651 while let Some(fre) = iter.next()? {
652 let start_pc = match fde.func_info.get_fde_type()? {
653 SFrameFDEType::PCInc => pc + fre.start_address.get() as u64,
654 SFrameFDEType::PCMask => fre.start_address.get() as u64,
655 };
656 let rest = match self.abi {
657 SFrameABI::AMD64LittleEndian => {
658 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
660 "fp"
661 } else {
662 "sp"
663 };
664 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
665 let fp = match fre.stack_offsets.get(1) {
666 Some(offset) => format!("c{:+}", offset.get()),
667 None => "u".to_string(), };
669 let ra = "f"; format!("{cfa:8} {fp:6} {ra}")
671 }
672 SFrameABI::AArch64LittleEndian => {
673 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
675 "fp"
676 } else {
677 "sp"
678 };
679 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
680 let fp = match fre.stack_offsets.get(1) {
681 Some(offset) => format!("c{:+}", offset.get()),
682 None => "u".to_string(), };
684 let ra = match fre.stack_offsets.get(2) {
685 Some(offset) => format!("c{:+}", offset.get()),
686 None => "u".to_string(), };
688 format!("{cfa:8} {fp:6} {ra}")
689 }
690 _ => todo!(),
691 };
692 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
693 }
694 writeln!(&mut s,)?;
695 }
696 Ok(s)
697 }
698
699 pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
701 SFrameFDEIterator {
702 section: self,
703 index: 0,
704 }
705 }
706
707 pub fn get_version(&self) -> SFrameVersion {
709 self.version
710 }
711
712 pub fn get_flags(&self) -> SFrameFlags {
714 self.flags
715 }
716
717 pub fn get_abi(&self) -> SFrameABI {
719 self.abi
720 }
721
722 pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
724 self.cfa_fixed_fp_offset
725 }
726
727 pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
729 self.cfa_fixed_ra_offset
730 }
731}
732
733pub struct SFrameFDEIterator<'a> {
735 section: &'a SFrameSection<'a>,
736 index: u32,
737}
738
739impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
740 type Item = SFrameFDE;
741 type Error = SFrameError;
742
743 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
744 let res = self.section.get_fde(self.index);
745 if let Ok(Some(_)) = res {
746 self.index += 1;
747 }
748 res
749 }
750}
751
752#[derive(Error, Debug)]
754pub enum SFrameError {
755 #[error("format error")]
757 Fmt(#[from] core::fmt::Error),
758 #[error("unexpected end of data")]
760 UnexpectedEndOfData,
761 #[error("invalid magic number")]
763 InvalidMagic,
764 #[error("unsupported version")]
766 UnsupportedVersion,
767 #[error("unsupported flags")]
769 UnsupportedFlags,
770 #[error("unsupported abi")]
772 UnsupportedABI,
773 #[error("unsupported fre type")]
775 UnsupportedFREType,
776 #[error("unsupported fre stack offset size")]
778 UnsupportedFREStackOffsetSize,
779}
780
781#[cfg(test)]
782mod tests {
783 use std::iter::zip;
784
785 use serde::{Deserialize, Serialize};
786 #[derive(Serialize, Deserialize)]
787 struct Testcase {
788 section_base: u64,
789 content: Vec<u8>,
790 groundtruth: String,
791 }
792
793 #[test]
794 fn test() {
795 for entry in std::fs::read_dir("testcases").unwrap() {
796 let entry = entry.unwrap();
797 let testcase: Testcase =
798 serde_json::from_reader(std::fs::File::open(entry.path()).unwrap()).unwrap();
799 let section =
800 crate::SFrameSection::from(&testcase.content, testcase.section_base).unwrap();
801 let s = section.to_string().unwrap();
802 let mut lines_expected: Vec<&str> = testcase.groundtruth.trim().split("\n").collect();
803
804 while let Some(line) = lines_expected.first() {
806 if line.contains("Header :") {
807 break;
808 }
809 lines_expected.remove(0);
810 }
811 let lines_actual: Vec<&str> = s.trim().split("\n").collect();
812
813 assert_eq!(lines_expected.len(), lines_actual.len());
815 for (expected, actual) in zip(lines_expected, lines_actual) {
816 let parts_expected: Vec<&str> =
817 expected.trim().split(" ").filter(|s| s.len() > 0).collect();
818 let parts_actual: Vec<&str> =
819 actual.trim().split(" ").filter(|s| s.len() > 0).collect();
820 assert_eq!(
821 parts_expected, parts_actual,
822 "\"{}\"({:?}) != \"{}\"({:?})",
823 expected, parts_expected, actual, parts_actual,
824 );
825 }
826 }
827 }
828}