1use std::{cmp::Ordering, fmt::Write};
6
7use bitflags::bitflags;
8use fallible_iterator::FallibleIterator;
9
10use crate::{SFrameError, SFrameResult, read_binary, read_struct};
11
12#[derive(Debug, Clone, Copy)]
16pub enum SFrameABI {
17 AArch64BigEndian,
19 AArch64LittleEndian,
21 AMD64LittleEndian,
23}
24
25bitflags! {
26 #[derive(Debug, Clone, Copy)]
30 pub struct SFrameFlags: u8 {
31 const SFRAME_F_FDE_SORTED = 0x1;
33 const SFRAME_F_FRAME_POINTER = 0x2;
35 }
36}
37
38#[derive(Debug, Clone, Copy)]
42#[allow(dead_code)]
43pub struct SFrameSection<'a> {
44 data: &'a [u8],
45 section_base: u64,
46 little_endian: bool,
47 flags: SFrameFlags,
48 abi: SFrameABI,
49 cfa_fixed_fp_offset: i8,
50 cfa_fixed_ra_offset: i8,
51 auxhdr_len: u8,
52 num_fdes: u32,
53 num_fres: u32,
54 fre_len: u32,
55 fdeoff: u32,
56 freoff: u32,
57}
58
59const SFRAME_MAGIC: u16 = 0xdee2;
61
62impl<'a> SFrameSection<'a> {
63 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
65 if data.len() < core::mem::size_of::<RawSFrameHeader>() {
67 return Err(SFrameError::UnexpectedEndOfData);
68 }
69
70 let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
72 let mut magic_bytes: [u8; 2] = [0; 2];
73 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
74 let magic_le = u16::from_le_bytes(magic_bytes);
75 let little_endian;
76 if magic_le == SFRAME_MAGIC {
77 little_endian = true;
78 } else {
79 let magic_be = u16::from_be_bytes(magic_bytes);
80 if magic_be == SFRAME_MAGIC {
81 little_endian = false;
82 } else {
83 return Err(SFrameError::InvalidMagic);
84 }
85 }
86
87 let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
89 let version = data[version_offset];
90 if version != 1 {
91 return Err(SFrameError::UnsupportedVersion);
92 }
93
94 let flags_offset = core::mem::offset_of!(RawSFrameHeader, flags);
96 let flags = data[flags_offset];
97 let flags = match SFrameFlags::from_bits(flags) {
98 Some(flags) => flags,
99 None => return Err(SFrameError::UnsupportedFlags),
100 };
101
102 let abi_offset = core::mem::offset_of!(RawSFrameHeader, abi_arch);
104 let abi = data[abi_offset];
105 let abi = match abi {
106 1 => SFrameABI::AArch64BigEndian,
107 2 => SFrameABI::AArch64LittleEndian,
108 3 => SFrameABI::AMD64LittleEndian,
109 _ => return Err(SFrameError::UnsupportedABI),
110 };
111
112 let cfa_fixed_fp_offset =
113 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_fp_offset)] as i8;
114 let cfa_fixed_ra_offset =
115 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_ra_offset)] as i8;
116 let auxhdr_len = data[core::mem::offset_of!(RawSFrameHeader, auxhdr_len)];
117
118 let num_fdes = read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32);
120 let fdeoff = read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32);
121 if data.len() - core::mem::size_of::<RawSFrameHeader>() < fdeoff as usize {
122 return Err(SFrameError::UnexpectedEndOfData);
123 } else if (data.len() - core::mem::size_of::<RawSFrameHeader>() - fdeoff as usize)
124 / core::mem::size_of::<RawSFrameFDE>()
125 < num_fdes as usize
126 {
127 return Err(SFrameError::UnexpectedEndOfData);
128 }
129
130 Ok(SFrameSection {
131 data,
132 section_base,
133 little_endian,
134 flags,
135 abi,
136 cfa_fixed_fp_offset,
137 cfa_fixed_ra_offset,
138 auxhdr_len,
139 num_fdes,
140 num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
141 fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
142 fdeoff,
143 freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
144 })
145 }
146
147 pub fn get_fde_count(&self) -> u32 {
149 self.num_fdes
150 }
151
152 pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
154 if index >= self.num_fdes {
155 return Ok(None);
157 }
158
159 let offset = self.fdeoff as usize
164 + index as usize * core::mem::size_of::<RawSFrameFDE>()
165 + core::mem::size_of::<RawSFrameHeader>();
166 if offset + core::mem::size_of::<RawSFrameFDE>() > self.data.len() {
167 return Err(SFrameError::UnexpectedEndOfData);
168 }
169
170 Ok(Some(SFrameFDE {
171 func_start_address: read_struct!(
172 RawSFrameFDE,
173 &self.data[offset..],
174 self.little_endian,
175 func_start_address,
176 i32
177 ),
178 func_size: read_struct!(
179 RawSFrameFDE,
180 &self.data[offset..],
181 self.little_endian,
182 func_size,
183 u32
184 ),
185 func_start_fre_off: read_struct!(
186 RawSFrameFDE,
187 &self.data[offset..],
188 self.little_endian,
189 func_start_fre_off,
190 u32
191 ),
192 func_num_fres: read_struct!(
193 RawSFrameFDE,
194 &self.data[offset..],
195 self.little_endian,
196 func_num_fres,
197 u32
198 ),
199 func_info: SFrameFDEInfo(
200 self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_info)],
201 ),
202 }))
203 }
204
205 pub fn to_string(&self) -> SFrameResult<String> {
207 let mut s = String::new();
208 writeln!(&mut s, "Header :")?;
209 writeln!(&mut s)?;
210 writeln!(&mut s, " Version: SFRAME_VERSION_1")?;
211 writeln!(
212 &mut s,
213 " Flags: {}",
214 self.flags
215 .iter_names()
216 .map(|(name, _flag)| name)
217 .collect::<Vec<_>>()
218 .join(" | ")
219 )?;
220 writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
221 writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
222 writeln!(&mut s)?;
223 writeln!(&mut s, "Function Index :")?;
224 writeln!(&mut s)?;
225 for i in 0..self.num_fdes {
226 let fde = self.get_fde(i)?.unwrap();
227 let pc = fde.get_pc(self);
228 let mut suffix = String::new();
229
230 if let SFrameAArch64PAuthKey::KeyB = fde.func_info.get_aarch64_pauth_key()? {
232 suffix += ", pauth = B key";
233 }
234 writeln!(
235 &mut s,
236 " func idx [{i}]: pc = 0x{:x}, size = {} bytes{}",
237 pc, fde.func_size, suffix
238 )?;
239
240 match fde.func_info.get_fde_type()? {
241 SFrameFDEType::PCInc => {
242 writeln!(&mut s, " STARTPC CFA FP RA")?;
243 }
244 SFrameFDEType::PCMask => {
245 writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
246 }
247 }
248 let mut iter = fde.iter_fre(self);
249 while let Some(fre) = iter.next()? {
250 let start_pc = match fde.func_info.get_fde_type()? {
251 SFrameFDEType::PCInc => pc + fre.start_address.get() as u64,
252 SFrameFDEType::PCMask => fre.start_address.get() as u64,
253 };
254 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
255 "fp"
256 } else {
257 "sp"
258 };
259 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
260 let fp = match fre.get_fp_offset(self) {
261 Some(offset) if self.cfa_fixed_fp_offset == 0 => format!("c{:+}", offset),
262 _ => "u".to_string(), };
264 let mut ra = match fre.get_ra_offset(self) {
265 Some(offset) if self.cfa_fixed_ra_offset == 0 => format!("c{:+}", offset),
266 _ => "u".to_string(), };
268 if fre.info.get_mangled_ra_p() {
269 ra.push_str("[s]");
271 }
272 let rest = format!("{cfa:8} {fp:6} {ra}");
273 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
274 }
275 writeln!(&mut s,)?;
276 }
277 Ok(s)
278 }
279
280 pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
282 SFrameFDEIterator {
283 section: self,
284 index: 0,
285 }
286 }
287
288 pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
290 if self.flags.contains(SFrameFlags::SFRAME_F_FDE_SORTED) {
291 let mut size = self.num_fdes;
294 if size == 0 {
295 return Ok(None);
296 }
297 let mut base = 0;
298
299 while size > 1 {
300 let half = size / 2;
301 let mid = base + half;
302
303 let cmp = self.get_fde(mid)?.unwrap().get_pc(self).cmp(&pc);
304 if cmp != Ordering::Greater {
305 base = mid;
306 }
307 size -= half;
308 }
309
310 let base_fde = self.get_fde(base)?.unwrap();
311 let base_pc = base_fde.get_pc(self);
312 let cmp = base_pc.cmp(&pc);
313 match cmp {
314 Ordering::Equal | Ordering::Less if pc < base_pc + base_fde.func_size as u64 => {
315 Ok(Some(base_fde))
316 }
317 _ => Ok(None),
318 }
319 } else {
320 let mut iter = self.iter_fde();
322 while let Some(fde) = iter.next()? {
323 let start = fde.get_pc(self);
324 if start <= pc && pc - start < fde.func_size as u64 {
325 return Ok(Some(fde));
326 }
327 }
328 Ok(None)
329 }
330 }
331
332 pub fn get_flags(&self) -> SFrameFlags {
334 self.flags
335 }
336
337 pub fn get_abi(&self) -> SFrameABI {
339 self.abi
340 }
341
342 pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
344 self.cfa_fixed_fp_offset
345 }
346
347 pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
349 self.cfa_fixed_ra_offset
350 }
351}
352
353#[repr(C, packed)]
357struct RawSFrameHeader {
358 magic: u16,
359 version: u8,
360 flags: u8,
361 abi_arch: u8,
362 cfa_fixed_fp_offset: i8,
363 cfa_fixed_ra_offset: i8,
364 auxhdr_len: u8,
365 num_fdes: u32,
366 num_fres: u32,
367 fre_len: u32,
368 fdeoff: u32,
369 freoff: u32,
370}
371
372#[repr(C, packed)]
376#[allow(dead_code)]
377struct RawSFrameFDE {
378 func_start_address: i32,
379 func_size: u32,
380 func_start_fre_off: u32,
381 func_num_fres: u32,
382 func_info: u8,
383}
384
385#[derive(Debug, Clone, Copy)]
391#[repr(transparent)]
392pub struct SFrameFDEInfo(u8);
393
394impl SFrameFDEInfo {
395 pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
397 let fretype = self.0 & 0b1111;
398 match fretype {
399 0 => Ok(SFrameFREType::Addr1),
400 1 => Ok(SFrameFREType::Addr2),
401 2 => Ok(SFrameFREType::Addr4),
402 _ => Err(SFrameError::UnsupportedFREType),
403 }
404 }
405
406 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
408 let fretype = (self.0 >> 4) & 0b1;
409 match fretype {
410 0 => Ok(SFrameFDEType::PCInc),
411 1 => Ok(SFrameFDEType::PCMask),
412 _ => unreachable!(),
413 }
414 }
415
416 pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
418 let fretype = (self.0 >> 5) & 0b1;
419 match fretype {
420 0 => Ok(SFrameAArch64PAuthKey::KeyA),
421 1 => Ok(SFrameAArch64PAuthKey::KeyB),
422 _ => unreachable!(),
423 }
424 }
425}
426
427#[derive(Debug, Clone, Copy)]
431pub enum SFrameFREType {
432 Addr1,
436 Addr2,
440 Addr4,
444}
445
446#[derive(Debug, Clone, Copy)]
450pub enum SFrameFDEType {
451 PCInc,
453 PCMask,
455}
456
457#[derive(Debug, Clone, Copy)]
461pub enum SFrameAArch64PAuthKey {
462 KeyA,
464 KeyB,
466}
467
468#[derive(Debug, Clone, Copy)]
472pub struct SFrameFDE {
473 pub func_start_address: i32,
475 pub func_size: u32,
477 pub func_start_fre_off: u32,
479 pub func_num_fres: u32,
481 pub func_info: SFrameFDEInfo,
483}
484
485impl SFrameFDE {
486 pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
488 (self.func_start_address as i64).wrapping_add_unsigned(section.section_base) as u64
489 }
490
491 pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
493 let offset = section.freoff as usize
502 + core::mem::size_of::<RawSFrameHeader>()
503 + self.func_start_fre_off as usize;
504 SFrameFREIterator {
505 fde: self,
506 section,
507 offset,
508 index: 0,
509 }
510 }
511
512 pub fn find_fre(
514 &self,
515 section: &SFrameSection<'_>,
516 pc: u64,
517 ) -> SFrameResult<Option<SFrameFRE>> {
518 let fde_pc = self.get_pc(section);
519 if pc < fde_pc || pc - fde_pc >= self.func_size as u64 {
520 return Ok(None);
522 }
523
524 match self.func_info.get_fde_type()? {
525 SFrameFDEType::PCInc => {
526 let mut last: Option<SFrameFRE> = None;
528 let mut iter = self.iter_fre(section);
529 while let Some(fre) = iter.next()? {
530 if fre.start_address.get() as u64 + fde_pc > pc {
531 break;
533 }
534 last = Some(fre);
535 }
536 if let Some(fre) = last {
537 if fre.start_address.get() as u64 + fde_pc <= pc {
539 return Ok(Some(fre));
540 }
541 }
542 Ok(None)
543 }
544 SFrameFDEType::PCMask => {
545 let mut iter = self.iter_fre(section);
547 while let Some(fre) = iter.next()? {
548 if fre.start_address.get() != 0
550 && pc % fre.start_address.get() as u64 >= fre.start_address.get() as u64
551 {
552 return Ok(Some(fre));
554 }
555 }
556 Ok(None)
557 }
558 }
559 }
560}
561
562#[derive(Debug, Clone, Copy)]
566pub enum SFrameFREStartAddress {
567 U8(u8),
568 U16(u16),
569 U32(u32),
570}
571
572impl SFrameFREStartAddress {
573 pub fn get(&self) -> u32 {
575 match self {
576 SFrameFREStartAddress::U8(i) => *i as u32,
577 SFrameFREStartAddress::U16(i) => *i as u32,
578 SFrameFREStartAddress::U32(i) => *i,
579 }
580 }
581}
582
583#[derive(Debug, Clone, Copy)]
587pub enum SFrameFREStackOffset {
588 I8(i8),
589 I16(i16),
590 I32(i32),
591}
592
593impl SFrameFREStackOffset {
594 pub fn get(&self) -> i32 {
596 match self {
597 SFrameFREStackOffset::I8(i) => *i as i32,
598 SFrameFREStackOffset::I16(i) => *i as i32,
599 SFrameFREStackOffset::I32(i) => *i,
600 }
601 }
602}
603
604#[derive(Debug, Clone)]
608pub struct SFrameFRE {
609 pub start_address: SFrameFREStartAddress,
611 pub info: SFrameFREInfo,
613 pub stack_offsets: Vec<SFrameFREStackOffset>,
615}
616
617impl SFrameFRE {
618 pub fn get_cfa_offset(&self, _section: &SFrameSection<'_>) -> Option<i32> {
620 self.stack_offsets.first().map(|offset| offset.get())
622 }
623
624 pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
626 if section.cfa_fixed_ra_offset != 0 {
628 return Some(section.cfa_fixed_ra_offset as i32);
629 }
630 self.stack_offsets.get(1).map(|offset| offset.get())
632 }
633
634 pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
636 if section.cfa_fixed_fp_offset != 0 {
638 return Some(section.cfa_fixed_fp_offset as i32);
639 }
640 if section.cfa_fixed_ra_offset != 0 {
642 return self.stack_offsets.get(1).map(|offset| offset.get());
643 }
644 self.stack_offsets.get(2).map(|offset| offset.get())
646 }
647}
648
649#[derive(Debug, Clone, Copy)]
653#[repr(transparent)]
654pub struct SFrameFREInfo(u8);
655
656impl SFrameFREInfo {
657 pub fn get_mangled_ra_p(&self) -> bool {
660 (self.0 >> 7) & 0b1 == 1
661 }
662
663 pub fn get_offset_size(&self) -> SFrameResult<usize> {
665 match (self.0 >> 5) & 0b11 {
666 0x0 => Ok(1),
668 0x1 => Ok(2),
670 0x2 => Ok(4),
672 _ => Err(SFrameError::UnsupportedFREStackOffsetSize),
673 }
674 }
675
676 pub fn get_offset_count(&self) -> u8 {
678 (self.0 >> 1) & 0b1111
679 }
680
681 pub fn get_cfa_base_reg_id(&self) -> u8 {
683 self.0 & 0b1
684 }
685}
686
687pub struct SFrameFREIterator<'a> {
689 fde: &'a SFrameFDE,
690 section: &'a SFrameSection<'a>,
691 index: u32,
692 offset: usize,
693}
694
695impl<'a> FallibleIterator for SFrameFREIterator<'a> {
696 type Item = SFrameFRE;
697 type Error = SFrameError;
698
699 fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
700 if self.index >= self.fde.func_num_fres {
701 return Ok(None);
702 }
703
704 let fre_type = self.fde.func_info.get_fre_type()?;
705 let entry_size = match fre_type {
706 SFrameFREType::Addr1 => 1 + 1,
707 SFrameFREType::Addr2 => 2 + 1,
708 SFrameFREType::Addr4 => 4 + 1,
709 } as usize;
710 let offset = self.offset;
711 if offset + entry_size > self.section.data.len() {
712 return Err(SFrameError::UnexpectedEndOfData);
713 }
714
715 let (start_address, info) = match self.fde.func_info.get_fre_type()? {
716 SFrameFREType::Addr1 => (
717 SFrameFREStartAddress::U8(self.section.data[offset]),
718 SFrameFREInfo(self.section.data[offset + 1]),
719 ),
720 SFrameFREType::Addr2 => (
721 SFrameFREStartAddress::U16(read_binary!(
722 self.section.data,
723 self.section.little_endian,
724 u16,
725 offset
726 )),
727 SFrameFREInfo(self.section.data[offset + 2]),
728 ),
729 SFrameFREType::Addr4 => (
730 SFrameFREStartAddress::U32(read_binary!(
731 self.section.data,
732 self.section.little_endian,
733 u32,
734 offset
735 )),
736 SFrameFREInfo(self.section.data[offset + 4]),
737 ),
738 };
739
740 let offset_size = info.get_offset_size()?;
741 let offset_count = info.get_offset_count() as usize;
742 let offset_total_size = offset_size * offset_count;
743 if offset + entry_size + offset_total_size > self.section.data.len() {
744 return Err(SFrameError::UnexpectedEndOfData);
745 }
746
747 let mut stack_offsets = vec![];
748 for i in 0..offset_count {
749 match offset_size {
750 1 => stack_offsets.push(SFrameFREStackOffset::I8(
751 self.section.data[offset + entry_size + i * offset_size] as i8,
752 )),
753 2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
754 self.section.data,
755 self.section.little_endian,
756 i16,
757 offset + entry_size + i * offset_size
758 ))),
759 4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
760 self.section.data,
761 self.section.little_endian,
762 i32,
763 offset + entry_size + i * offset_size
764 ))),
765 _ => unreachable!(),
766 }
767 }
768
769 self.offset += entry_size + offset_total_size;
770 self.index += 1;
771
772 Ok(Some(SFrameFRE {
773 start_address,
774 info,
775 stack_offsets,
776 }))
777 }
778}
779
780pub struct SFrameFDEIterator<'a> {
782 section: &'a SFrameSection<'a>,
783 index: u32,
784}
785
786impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
787 type Item = SFrameFDE;
788 type Error = SFrameError;
789
790 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
791 let res = self.section.get_fde(self.index);
792 if let Ok(Some(_)) = res {
793 self.index += 1;
794 }
795 res
796 }
797}