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 S390XBigEndian,
25}
26
27pub mod s390x {
31 pub const SFRAME_S390X_SP_VAL_OFFSET: i32 = -160;
34
35 pub const SFRAME_S390X_CFA_OFFSET_ADJUSTMENT: i32 = SFRAME_S390X_SP_VAL_OFFSET;
38
39 pub const SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR: i32 = 8;
42
43 pub const SFRAME_FRE_RA_OFFSET_INVALID: i32 = 0;
46
47 pub const fn cfa_offset_decode(offset: i32) -> i32 {
49 (offset * SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR) - SFRAME_S390X_CFA_OFFSET_ADJUSTMENT
50 }
51
52 pub const fn offset_is_regnum(offset: i32) -> bool {
54 (offset & 1) != 0
55 }
56
57 pub const fn offset_decode_regnum(offset: i32) -> i32 {
59 offset >> 1
60 }
61}
62
63bitflags! {
64 #[derive(Debug, Clone, Copy)]
68 pub struct SFrameFlags: u8 {
69 const SFRAME_F_FDE_SORTED = 0x1;
71 const SFRAME_F_FRAME_POINTER = 0x2;
73 const SFRAME_F_FDE_FUNC_START_PCREL = 0x4;
75 }
76}
77
78#[derive(Debug, Clone, Copy)]
82#[allow(dead_code)]
83pub struct SFrameSection<'a> {
84 data: &'a [u8],
85 section_base: u64,
86 little_endian: bool,
87 flags: SFrameFlags,
88 abi: SFrameABI,
89 cfa_fixed_fp_offset: i8,
90 cfa_fixed_ra_offset: i8,
91 auxhdr_len: u8,
92 num_fdes: u32,
93 num_fres: u32,
94 fre_len: u32,
95 fdeoff: u32,
96 freoff: u32,
97}
98
99const SFRAME_MAGIC: u16 = 0xdee2;
101
102impl<'a> SFrameSection<'a> {
103 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
105 if data.len() < core::mem::size_of::<RawSFrameHeader>() {
107 return Err(SFrameError::UnexpectedEndOfData);
108 }
109
110 let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
112 let mut magic_bytes: [u8; 2] = [0; 2];
113 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
114 let magic_le = u16::from_le_bytes(magic_bytes);
115 let little_endian;
116 if magic_le == SFRAME_MAGIC {
117 little_endian = true;
118 } else {
119 let magic_be = u16::from_be_bytes(magic_bytes);
120 if magic_be == SFRAME_MAGIC {
121 little_endian = false;
122 } else {
123 return Err(SFrameError::InvalidMagic);
124 }
125 }
126
127 let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
129 let version = data[version_offset];
130 if version != 2 {
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 let num_fdes = read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32);
161 let fdeoff = read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32);
162 if data.len() - core::mem::size_of::<RawSFrameHeader>() < fdeoff as usize {
163 return Err(SFrameError::UnexpectedEndOfData);
164 } else if (data.len() - core::mem::size_of::<RawSFrameHeader>() - fdeoff as usize)
165 / core::mem::size_of::<RawSFrameFDE>()
166 < num_fdes as usize
167 {
168 return Err(SFrameError::UnexpectedEndOfData);
169 }
170
171 Ok(SFrameSection {
172 data,
173 section_base,
174 little_endian,
175 flags,
176 abi,
177 cfa_fixed_fp_offset,
178 cfa_fixed_ra_offset,
179 auxhdr_len,
180 num_fdes,
181 num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
182 fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
183 fdeoff,
184 freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
185 })
186 }
187
188 pub fn get_fde_count(&self) -> u32 {
190 self.num_fdes
191 }
192
193 pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
195 if index >= self.num_fdes {
196 return Ok(None);
198 }
199
200 let offset = self.fdeoff as usize
205 + index as usize * core::mem::size_of::<RawSFrameFDE>()
206 + core::mem::size_of::<RawSFrameHeader>();
207 if offset + core::mem::size_of::<RawSFrameFDE>() > self.data.len() {
208 return Err(SFrameError::UnexpectedEndOfData);
209 }
210
211 Ok(Some(SFrameFDE {
212 offset,
213 func_start_address: read_struct!(
214 RawSFrameFDE,
215 &self.data[offset..],
216 self.little_endian,
217 func_start_address,
218 i32
219 ),
220 func_size: read_struct!(
221 RawSFrameFDE,
222 &self.data[offset..],
223 self.little_endian,
224 func_size,
225 u32
226 ),
227 func_start_fre_off: read_struct!(
228 RawSFrameFDE,
229 &self.data[offset..],
230 self.little_endian,
231 func_start_fre_off,
232 u32
233 ),
234 func_num_fres: read_struct!(
235 RawSFrameFDE,
236 &self.data[offset..],
237 self.little_endian,
238 func_num_fres,
239 u32
240 ),
241 func_info: SFrameFDEInfo(
242 self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_info)],
243 ),
244 func_rep_size: self.data[offset + core::mem::offset_of!(RawSFrameFDE, func_rep_size)],
245 }))
246 }
247
248 pub fn to_string(&self) -> SFrameResult<String> {
250 let mut s = String::new();
251 writeln!(&mut s, "Header :")?;
252 writeln!(&mut s)?;
253 writeln!(&mut s, " Version: SFRAME_VERSION_2")?;
254 writeln!(
255 &mut s,
256 " Flags: {}",
257 self.flags
258 .iter_names()
259 .map(|(name, _flag)| name)
260 .collect::<Vec<_>>()
261 .join(",\n ")
262 )?;
263 if self.cfa_fixed_fp_offset != 0 {
264 writeln!(
265 &mut s,
266 " CFA fixed FP offset: {:?}",
267 self.cfa_fixed_fp_offset
268 )?;
269 }
270 if self.cfa_fixed_ra_offset != 0 {
271 writeln!(
272 &mut s,
273 " CFA fixed RA offset: {:?}",
274 self.cfa_fixed_ra_offset
275 )?;
276 }
277 writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
278 writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
279 writeln!(&mut s)?;
280 writeln!(&mut s, "Function Index :")?;
281 writeln!(&mut s)?;
282 for i in 0..self.num_fdes {
283 let fde = self.get_fde(i)?.unwrap();
284 let pc = fde.get_pc(self);
285 let mut suffix = String::new();
286
287 if let SFrameAArch64PAuthKey::KeyB = fde.func_info.get_aarch64_pauth_key()? {
289 suffix += ", pauth = B key";
290 }
291
292 writeln!(
293 &mut s,
294 " func idx [{i}]: pc = 0x{:x}, size = {} bytes{}",
295 pc, fde.func_size, suffix
296 )?;
297
298 match fde.func_info.get_fde_type()? {
299 SFrameFDEType::PCInc => {
300 writeln!(&mut s, " STARTPC CFA FP RA")?;
301 }
302 SFrameFDEType::PCMask => {
303 writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
304 }
305 }
306 let mut iter = fde.iter_fre(self);
307 while let Some(fre) = iter.next()? {
308 let start_pc = match fde.func_info.get_fde_type()? {
309 SFrameFDEType::PCInc => pc + fre.start_address.get() as u64,
310 SFrameFDEType::PCMask => fre.start_address.get() as u64,
311 };
312 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
313 "fp"
314 } else {
315 "sp"
316 };
317 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
318 let fp = match fre.get_fp_offset(self) {
319 Some(offset) => format!("c{:+}", offset),
320 None => "u".to_string(), };
322 let mut ra = if self.cfa_fixed_ra_offset != 0 {
323 "f".to_string() } else {
325 match fre.get_ra_offset(self) {
326 Some(offset) => format!("c{:+}", offset),
327 None => "u".to_string(), }
329 };
330 if fre.info.get_mangled_ra_p() {
331 ra.push_str("[s]");
333 }
334 let rest = format!("{cfa:8} {fp:6} {ra}");
335 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
336 }
337 writeln!(&mut s,)?;
338 }
339 Ok(s)
340 }
341
342 pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
344 SFrameFDEIterator {
345 section: self,
346 index: 0,
347 }
348 }
349
350 pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
352 if self.flags.contains(SFrameFlags::SFRAME_F_FDE_SORTED) {
353 let mut size = self.num_fdes;
356 if size == 0 {
357 return Ok(None);
358 }
359 let mut base = 0;
360
361 while size > 1 {
362 let half = size / 2;
363 let mid = base + half;
364
365 let cmp = self.get_fde(mid)?.unwrap().get_pc(self).cmp(&pc);
366 if cmp != Ordering::Greater {
367 base = mid;
368 }
369 size -= half;
370 }
371
372 let base_fde = self.get_fde(base)?.unwrap();
373 let base_pc = base_fde.get_pc(self);
374 let cmp = base_pc.cmp(&pc);
375 match cmp {
376 Ordering::Equal | Ordering::Less if pc < base_pc + base_fde.func_size as u64 => {
377 Ok(Some(base_fde))
378 }
379 _ => Ok(None),
380 }
381 } else {
382 let mut iter = self.iter_fde();
384 while let Some(fde) = iter.next()? {
385 let start = fde.get_pc(self);
386 if start <= pc && pc - start < fde.func_size as u64 {
387 return Ok(Some(fde));
388 }
389 }
390 Ok(None)
391 }
392 }
393
394 pub fn get_flags(&self) -> SFrameFlags {
396 self.flags
397 }
398
399 pub fn get_abi(&self) -> SFrameABI {
401 self.abi
402 }
403
404 pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
406 self.cfa_fixed_fp_offset
407 }
408
409 pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
411 self.cfa_fixed_ra_offset
412 }
413}
414
415#[repr(C, packed)]
419struct RawSFrameHeader {
420 magic: u16,
421 version: u8,
422 flags: u8,
423 abi_arch: u8,
424 cfa_fixed_fp_offset: i8,
425 cfa_fixed_ra_offset: i8,
426 auxhdr_len: u8,
427 num_fdes: u32,
428 num_fres: u32,
429 fre_len: u32,
430 fdeoff: u32,
431 freoff: u32,
432}
433
434#[repr(C, packed)]
438#[allow(dead_code)]
439struct RawSFrameFDE {
440 func_start_address: i32,
441 func_size: u32,
442 func_start_fre_off: u32,
443 func_num_fres: u32,
444 func_info: u8,
445 func_rep_size: u8,
446 func_padding2: u16,
447}
448
449#[derive(Debug, Clone, Copy)]
453#[repr(transparent)]
454pub struct SFrameFDEInfo(u8);
455
456impl SFrameFDEInfo {
457 pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
459 let fretype = self.0 & 0b1111;
460 match fretype {
461 0 => Ok(SFrameFREType::Addr1),
462 1 => Ok(SFrameFREType::Addr2),
463 2 => Ok(SFrameFREType::Addr4),
464 _ => Err(SFrameError::UnsupportedFREType),
465 }
466 }
467
468 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
470 let fretype = (self.0 >> 4) & 0b1;
471 match fretype {
472 0 => Ok(SFrameFDEType::PCInc),
473 1 => Ok(SFrameFDEType::PCMask),
474 _ => unreachable!(),
475 }
476 }
477
478 pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
480 let fretype = (self.0 >> 5) & 0b1;
481 match fretype {
482 0 => Ok(SFrameAArch64PAuthKey::KeyA),
483 1 => Ok(SFrameAArch64PAuthKey::KeyB),
484 _ => unreachable!(),
485 }
486 }
487}
488
489#[derive(Debug, Clone, Copy)]
493pub enum SFrameFREType {
494 Addr1,
498 Addr2,
502 Addr4,
506}
507
508#[derive(Debug, Clone, Copy)]
512pub enum SFrameFDEType {
513 PCInc,
515 PCMask,
517}
518
519#[derive(Debug, Clone, Copy)]
523pub enum SFrameAArch64PAuthKey {
524 KeyA,
526 KeyB,
528}
529
530#[derive(Debug, Clone, Copy)]
534pub struct SFrameFDE {
535 offset: usize,
537 pub func_start_address: i32,
544 pub func_size: u32,
547 pub func_start_fre_off: u32,
550 pub func_num_fres: u32,
553 pub func_info: SFrameFDEInfo,
556 pub func_rep_size: u8,
560}
561
562impl SFrameFDE {
563 pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
565 if section
571 .flags
572 .contains(SFrameFlags::SFRAME_F_FDE_FUNC_START_PCREL)
573 {
574 (self.func_start_address as i64)
575 .wrapping_add_unsigned(self.offset as u64)
576 .wrapping_add_unsigned(section.section_base) as u64
577 } else {
578 (self.func_start_address as i64).wrapping_add_unsigned(section.section_base) as u64
579 }
580 }
581
582 pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
584 let offset = section.freoff as usize
593 + core::mem::size_of::<RawSFrameHeader>()
594 + self.func_start_fre_off as usize;
595 SFrameFREIterator {
596 fde: self,
597 section,
598 offset,
599 index: 0,
600 }
601 }
602
603 pub fn find_fre(
605 &self,
606 section: &SFrameSection<'_>,
607 pc: u64,
608 ) -> SFrameResult<Option<SFrameFRE>> {
609 let fde_pc = self.get_pc(section);
610 if pc < fde_pc || pc - fde_pc >= self.func_size as u64 {
611 return Ok(None);
613 }
614
615 match self.func_info.get_fde_type()? {
616 SFrameFDEType::PCInc => {
617 let mut last: Option<SFrameFRE> = None;
619 let mut iter = self.iter_fre(section);
620 while let Some(fre) = iter.next()? {
621 if fre.start_address.get() as u64 + fde_pc > pc {
622 break;
624 }
625 last = Some(fre);
626 }
627 if let Some(fre) = last {
628 if fre.start_address.get() as u64 + fde_pc <= pc {
630 return Ok(Some(fre));
631 }
632 }
633 Ok(None)
634 }
635 SFrameFDEType::PCMask => {
636 let mut iter = self.iter_fre(section);
638 while let Some(fre) = iter.next()? {
639 if self.func_rep_size != 0
641 && pc % self.func_rep_size as u64 >= fre.start_address.get() as u64
642 {
643 return Ok(Some(fre));
645 }
646 }
647 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, section: &SFrameSection<'_>) -> Option<i32> {
711 self.stack_offsets.first().map(|offset| {
712 let offset = offset.get();
713 match section.abi {
714 SFrameABI::S390XBigEndian => s390x::cfa_offset_decode(offset),
716 _ => offset,
717 }
718 })
719 }
720
721 pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
728 match section.abi {
729 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
731 self.stack_offsets.get(1).map(|offset| offset.get())
732 }
733 SFrameABI::AMD64LittleEndian => Some(section.cfa_fixed_ra_offset as i32),
735 SFrameABI::S390XBigEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
737 }
738 }
739
740 pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
746 match section.abi {
747 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
749 self.stack_offsets.get(2).map(|offset| offset.get())
750 }
751 SFrameABI::AMD64LittleEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
753 SFrameABI::S390XBigEndian => self.stack_offsets.get(2).map(|offset| offset.get()),
755 }
756 }
757}
758
759#[derive(Debug, Clone, Copy)]
763#[repr(transparent)]
764pub struct SFrameFREInfo(u8);
765
766impl SFrameFREInfo {
767 pub fn get_mangled_ra_p(&self) -> bool {
770 (self.0 >> 7) & 0b1 == 1
771 }
772
773 pub fn get_offset_size(&self) -> SFrameResult<usize> {
775 match (self.0 >> 5) & 0b11 {
776 0x0 => Ok(1),
778 0x1 => Ok(2),
780 0x2 => Ok(4),
782 _ => Err(SFrameError::UnsupportedFREStackOffsetSize),
783 }
784 }
785
786 pub fn get_offset_count(&self) -> u8 {
788 (self.0 >> 1) & 0b1111
789 }
790
791 pub fn get_cfa_base_reg_id(&self) -> u8 {
793 self.0 & 0b1
794 }
795}
796
797pub struct SFrameFREIterator<'a> {
799 fde: &'a SFrameFDE,
800 section: &'a SFrameSection<'a>,
801 index: u32,
802 offset: usize,
803}
804
805impl<'a> FallibleIterator for SFrameFREIterator<'a> {
806 type Item = SFrameFRE;
807 type Error = SFrameError;
808
809 fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
810 if self.index >= self.fde.func_num_fres {
811 return Ok(None);
812 }
813
814 let fre_type = self.fde.func_info.get_fre_type()?;
815 let entry_size = match fre_type {
816 SFrameFREType::Addr1 => 1 + 1,
817 SFrameFREType::Addr2 => 2 + 1,
818 SFrameFREType::Addr4 => 4 + 1,
819 } as usize;
820 let offset = self.offset;
821 if offset + entry_size > self.section.data.len() {
822 return Err(SFrameError::UnexpectedEndOfData);
823 }
824
825 let (start_address, info) = match self.fde.func_info.get_fre_type()? {
826 SFrameFREType::Addr1 => (
827 SFrameFREStartAddress::U8(self.section.data[offset]),
828 SFrameFREInfo(self.section.data[offset + 1]),
829 ),
830 SFrameFREType::Addr2 => (
831 SFrameFREStartAddress::U16(read_binary!(
832 self.section.data,
833 self.section.little_endian,
834 u16,
835 offset
836 )),
837 SFrameFREInfo(self.section.data[offset + 2]),
838 ),
839 SFrameFREType::Addr4 => (
840 SFrameFREStartAddress::U32(read_binary!(
841 self.section.data,
842 self.section.little_endian,
843 u32,
844 offset
845 )),
846 SFrameFREInfo(self.section.data[offset + 4]),
847 ),
848 };
849
850 let offset_size = info.get_offset_size()?;
851 let offset_count = info.get_offset_count() as usize;
852 let offset_total_size = offset_size * offset_count;
853 if offset + entry_size + offset_total_size > self.section.data.len() {
854 return Err(SFrameError::UnexpectedEndOfData);
855 }
856
857 let mut stack_offsets = vec![];
858 for i in 0..offset_count {
859 match offset_size {
860 1 => stack_offsets.push(SFrameFREStackOffset::I8(
861 self.section.data[offset + entry_size + i * offset_size] as i8,
862 )),
863 2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
864 self.section.data,
865 self.section.little_endian,
866 i16,
867 offset + entry_size + i * offset_size
868 ))),
869 4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
870 self.section.data,
871 self.section.little_endian,
872 i32,
873 offset + entry_size + i * offset_size
874 ))),
875 _ => unreachable!(),
876 }
877 }
878
879 self.offset += entry_size + offset_total_size;
880 self.index += 1;
881
882 Ok(Some(SFrameFRE {
883 start_address,
884 info,
885 stack_offsets,
886 }))
887 }
888}
889
890pub struct SFrameFDEIterator<'a> {
892 section: &'a SFrameSection<'a>,
893 index: u32,
894}
895
896impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
897 type Item = SFrameFDE;
898 type Error = SFrameError;
899
900 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
901 let res = self.section.get_fde(self.index);
902 if let Ok(Some(_)) = res {
903 self.index += 1;
904 }
905 res
906 }
907}