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
102fn get_regname_from_dwarf(regnum: i32, abi: SFrameABI) -> String {
104 match (regnum, abi) {
105 (6, SFrameABI::AMD64LittleEndian) => "fp".to_string(),
107 (7, SFrameABI::AMD64LittleEndian) => "sp".to_string(),
109 _ => format!("r{}", regnum),
110 }
111}
112
113fn flex_recovery_rule_to_string(rule: &SFrameFlexRecoveryRule, abi: SFrameABI) -> String {
115 match (
116 rule.control.is_padding(),
117 rule.control.reg_p(),
118 rule.control.deref_p(),
119 ) {
120 (true, _, _) => {
121 format!("U")
123 }
124 (false, true, true) => {
125 format!(
127 "({}{:+})",
128 get_regname_from_dwarf(rule.control.regnum(), abi),
129 rule.offset
130 )
131 }
132 (false, true, false) => {
133 format!(
135 "{}{:+}",
136 get_regname_from_dwarf(rule.control.regnum(), abi),
137 rule.offset
138 )
139 }
140 (false, false, _) => {
141 format!("c{:+}", rule.offset)
143 }
144 }
145}
146
147impl<'a> SFrameSection<'a> {
148 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
150 if data.len() < core::mem::size_of::<RawSFrameHeader>() {
152 return Err(SFrameError::UnexpectedEndOfData);
153 }
154
155 let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
157 let mut magic_bytes: [u8; 2] = [0; 2];
158 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
159 let magic_le = u16::from_le_bytes(magic_bytes);
160 let little_endian;
161 if magic_le == SFRAME_MAGIC {
162 little_endian = true;
163 } else {
164 let magic_be = u16::from_be_bytes(magic_bytes);
165 if magic_be == SFRAME_MAGIC {
166 little_endian = false;
167 } else {
168 return Err(SFrameError::InvalidMagic);
169 }
170 }
171
172 let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
174 let version = data[version_offset];
175 if version != 3 {
176 return Err(SFrameError::UnsupportedVersion);
177 }
178
179 let flags_offset = core::mem::offset_of!(RawSFrameHeader, flags);
181 let flags = data[flags_offset];
182 let flags = match SFrameFlags::from_bits(flags) {
183 Some(flags) => flags,
184 None => return Err(SFrameError::UnsupportedFlags),
185 };
186
187 let abi_offset = core::mem::offset_of!(RawSFrameHeader, abi_arch);
189 let abi = data[abi_offset];
190 let abi = match abi {
191 1 => SFrameABI::AArch64BigEndian,
192 2 => SFrameABI::AArch64LittleEndian,
193 3 => SFrameABI::AMD64LittleEndian,
194 4 => SFrameABI::S390XBigEndian,
195 _ => return Err(SFrameError::UnsupportedABI),
196 };
197
198 let cfa_fixed_fp_offset =
199 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_fp_offset)] as i8;
200 let cfa_fixed_ra_offset =
201 data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_ra_offset)] as i8;
202 let auxhdr_len = data[core::mem::offset_of!(RawSFrameHeader, auxhdr_len)];
203
204 let num_fdes = read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32);
206 let fdeoff = read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32);
207 if data.len() - core::mem::size_of::<RawSFrameHeader>() < fdeoff as usize {
208 return Err(SFrameError::UnexpectedEndOfData);
209 } else if (data.len() - core::mem::size_of::<RawSFrameHeader>() - fdeoff as usize)
210 / core::mem::size_of::<RawSFrameFDEIndex>()
211 < num_fdes as usize
212 {
213 return Err(SFrameError::UnexpectedEndOfData);
214 }
215
216 Ok(SFrameSection {
217 data,
218 section_base,
219 little_endian,
220 flags,
221 abi,
222 cfa_fixed_fp_offset,
223 cfa_fixed_ra_offset,
224 auxhdr_len,
225 num_fdes,
226 num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
227 fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
228 fdeoff,
229 freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
230 })
231 }
232
233 pub fn get_fde_count(&self) -> u32 {
235 self.num_fdes
236 }
237
238 pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
240 if index >= self.num_fdes {
241 return Ok(None);
243 }
244
245 let offset = self.fdeoff as usize
250 + index as usize * core::mem::size_of::<RawSFrameFDEIndex>()
251 + core::mem::size_of::<RawSFrameHeader>();
252 if offset + core::mem::size_of::<RawSFrameFDEIndex>() > self.data.len() {
253 return Err(SFrameError::UnexpectedEndOfData);
254 }
255
256 let func_start_fre_off = read_struct!(
259 RawSFrameFDEIndex,
260 &self.data[offset..],
261 self.little_endian,
262 func_start_fre_off,
263 u32
264 );
265
266 let fre_offset = self.freoff as usize
267 + core::mem::size_of::<RawSFrameHeader>()
268 + func_start_fre_off as usize;
269 let func_num_fres = read_struct!(
270 RawSFrameFDEAttr,
271 &self.data[fre_offset..],
272 self.little_endian,
273 func_num_fres,
274 u16
275 );
276 let func_info = read_struct!(
277 RawSFrameFDEAttr,
278 &self.data[fre_offset..],
279 self.little_endian,
280 func_info,
281 u8
282 );
283 let func_info2 = read_struct!(
284 RawSFrameFDEAttr,
285 &self.data[fre_offset..],
286 self.little_endian,
287 func_info2,
288 u8
289 );
290 let func_rep_size = read_struct!(
291 RawSFrameFDEAttr,
292 &self.data[fre_offset..],
293 self.little_endian,
294 func_rep_size,
295 u8
296 );
297
298 Ok(Some(SFrameFDE {
299 offset,
300 func_start_offset: read_struct!(
301 RawSFrameFDEIndex,
302 &self.data[offset..],
303 self.little_endian,
304 func_start_offset,
305 i64
306 ),
307 func_size: read_struct!(
308 RawSFrameFDEIndex,
309 &self.data[offset..],
310 self.little_endian,
311 func_size,
312 u32
313 ),
314 func_start_fre_off,
315 func_num_fres,
316 func_info: SFrameFDEInfo(func_info),
317 func_info2: SFrameFDEInfo2(func_info2),
318 func_rep_size,
319 }))
320 }
321
322 pub fn to_string(&self) -> SFrameResult<String> {
324 let mut s = String::new();
325 writeln!(&mut s, "Header :")?;
326 writeln!(&mut s)?;
327 writeln!(&mut s, " Version: SFRAME_VERSION_3")?;
328 writeln!(
329 &mut s,
330 " Flags: {}",
331 self.flags
332 .iter_names()
333 .map(|(name, _flag)| name)
334 .collect::<Vec<_>>()
335 .join(",\n ")
336 )?;
337 if self.cfa_fixed_fp_offset != 0 {
338 writeln!(
339 &mut s,
340 " CFA fixed FP offset: {:?}",
341 self.cfa_fixed_fp_offset
342 )?;
343 }
344 if self.cfa_fixed_ra_offset != 0 {
345 writeln!(
346 &mut s,
347 " CFA fixed RA offset: {:?}",
348 self.cfa_fixed_ra_offset
349 )?;
350 }
351 writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
352 writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
353 writeln!(&mut s)?;
354 writeln!(&mut s, "Function Index :")?;
355 writeln!(&mut s)?;
356 for i in 0..self.num_fdes {
357 let fde = self.get_fde(i)?.unwrap();
358 let pc = fde.get_pc(self);
359 let mut suffix = String::new();
360
361 let mut attrs = "".to_string();
362 if fde.func_info.is_signal_frame()? {
363 attrs.push('S');
364 }
365 if let Ok(SFrameFDEType::Flex) = fde.func_info2.get_fde_type() {
366 attrs.push('F');
367 }
368
369 if !attrs.is_empty() {
370 suffix += &format!(", attr = \"{}\"", attrs);
371 };
372
373 if let SFrameAArch64PAuthKey::KeyB = fde.func_info.get_aarch64_pauth_key()? {
375 suffix += ", pauth = B key";
376 }
377
378 writeln!(
379 &mut s,
380 " func idx [{i}]: pc = 0x{:x}, size = {} bytes{}",
381 pc, fde.func_size, suffix
382 )?;
383
384 match fde.func_info.get_fde_pctype()? {
385 SFrameFDEPCType::PCInc => {
386 writeln!(&mut s, " STARTPC CFA FP RA")?;
387 }
388 SFrameFDEPCType::PCMask => {
389 writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
390 }
391 }
392 let mut iter = fde.iter_fre(self);
393 while let Some(fre) = iter.next()? {
394 let start_pc = match fde.func_info.get_fde_pctype()? {
395 SFrameFDEPCType::PCInc => pc + fre.start_address.get() as u64,
396 SFrameFDEPCType::PCMask => fre.start_address.get() as u64,
397 };
398
399 match fde.func_info2.get_fde_type() {
400 Ok(SFrameFDEType::Default) => {
401 if fre.stack_offsets.is_empty() {
403 writeln!(&mut s, " {:016x} RA undefined", start_pc)?;
405 } else {
406 let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
407 "fp"
408 } else {
409 "sp"
410 };
411 let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
412 let fp = match fre.get_fp_offset(self) {
413 Some(offset) => format!("c{:+}", offset),
414 None => "u".to_string(), };
416 let mut ra = if self.cfa_fixed_ra_offset != 0 {
417 "f".to_string() } else {
419 match fre.get_ra_offset(self) {
420 Some(offset) => format!("c{:+}", offset),
421 None => "u".to_string(), }
423 };
424 if fre.info.get_mangled_ra_p() {
425 ra.push_str("[s]");
427 }
428 let rest = format!("{cfa:8} {fp:6} {ra}");
429 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
430 }
431 }
432 Ok(SFrameFDEType::Flex) => {
433 if let Some(rules) = fre.get_flex_recovery_rules() {
435 let cfa = flex_recovery_rule_to_string(&rules.cfa, self.abi);
436 let fp = if let Some(fp_rule) = rules.fp {
437 flex_recovery_rule_to_string(&fp_rule, self.abi)
438 } else {
439 "u".to_string()
440 };
441 let ra = if let Some(ra_rule) = rules.ra {
442 flex_recovery_rule_to_string(&ra_rule, self.abi)
443 } else {
444 if self.cfa_fixed_ra_offset != 0 {
445 "f".to_string()
446 } else {
447 "u".to_string()
448 }
449 };
450 let rest = format!("{cfa:8} {fp:6} {ra}");
451 writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
452 } else {
453 writeln!(&mut s, " {:016x} RA undefined", start_pc)?;
455 }
456 }
457 _ => {}
458 }
459 }
460 writeln!(&mut s,)?;
461 }
462 Ok(s)
463 }
464
465 pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
467 SFrameFDEIterator {
468 section: self,
469 index: 0,
470 }
471 }
472
473 pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
475 if self.flags.contains(SFrameFlags::SFRAME_F_FDE_SORTED) {
476 let mut size = self.num_fdes;
479 if size == 0 {
480 return Ok(None);
481 }
482 let mut base = 0;
483
484 while size > 1 {
485 let half = size / 2;
486 let mid = base + half;
487
488 let cmp = self.get_fde(mid)?.unwrap().get_pc(self).cmp(&pc);
489 if cmp != Ordering::Greater {
490 base = mid;
491 }
492 size -= half;
493 }
494
495 let base_fde = self.get_fde(base)?.unwrap();
496 let base_pc = base_fde.get_pc(self);
497 let cmp = base_pc.cmp(&pc);
498 match cmp {
499 Ordering::Equal | Ordering::Less if pc < base_pc + base_fde.func_size as u64 => {
500 Ok(Some(base_fde))
501 }
502 _ => Ok(None),
503 }
504 } else {
505 let mut iter = self.iter_fde();
507 while let Some(fde) = iter.next()? {
508 let start = fde.get_pc(self);
509 if start <= pc && pc - start < fde.func_size as u64 {
510 return Ok(Some(fde));
511 }
512 }
513 Ok(None)
514 }
515 }
516
517 pub fn get_flags(&self) -> SFrameFlags {
519 self.flags
520 }
521
522 pub fn get_abi(&self) -> SFrameABI {
524 self.abi
525 }
526
527 pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
529 self.cfa_fixed_fp_offset
530 }
531
532 pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
534 self.cfa_fixed_ra_offset
535 }
536}
537
538#[repr(C, packed)]
542struct RawSFrameHeader {
543 magic: u16,
544 version: u8,
545 flags: u8,
546 abi_arch: u8,
547 cfa_fixed_fp_offset: i8,
548 cfa_fixed_ra_offset: i8,
549 auxhdr_len: u8,
550 num_fdes: u32,
551 num_fres: u32,
552 fre_len: u32,
553 fdeoff: u32,
554 freoff: u32,
555}
556
557#[repr(C, packed)]
561#[allow(dead_code)]
562struct RawSFrameFDEIndex {
563 func_start_offset: i64,
564 func_size: u32,
565 func_start_fre_off: u32,
566}
567
568#[repr(C, packed)]
572#[allow(dead_code)]
573struct RawSFrameFDEAttr {
574 func_num_fres: u16,
575 func_info: u8,
576 func_info2: u8,
577 func_rep_size: u8,
578}
579
580#[derive(Debug, Clone, Copy)]
584#[repr(transparent)]
585pub struct SFrameFDEInfo(u8);
586
587impl SFrameFDEInfo {
588 pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
590 let fretype = self.0 & 0b1111;
591 match fretype {
592 0 => Ok(SFrameFREType::Addr1),
593 1 => Ok(SFrameFREType::Addr2),
594 2 => Ok(SFrameFREType::Addr4),
595 _ => Err(SFrameError::UnsupportedFREType),
596 }
597 }
598
599 pub fn get_fde_pctype(&self) -> SFrameResult<SFrameFDEPCType> {
601 let fretype = (self.0 >> 4) & 0b1;
602 match fretype {
603 0 => Ok(SFrameFDEPCType::PCInc),
604 1 => Ok(SFrameFDEPCType::PCMask),
605 _ => unreachable!(),
606 }
607 }
608
609 pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
611 let fretype = (self.0 >> 5) & 0b1;
612 match fretype {
613 0 => Ok(SFrameAArch64PAuthKey::KeyA),
614 1 => Ok(SFrameAArch64PAuthKey::KeyB),
615 _ => unreachable!(),
616 }
617 }
618
619 pub fn is_signal_frame(&self) -> SFrameResult<bool> {
621 let fretype = (self.0 >> 7) & 0b1;
622 match fretype {
623 0 => Ok(false),
624 1 => Ok(true),
625 _ => unreachable!(),
626 }
627 }
628}
629
630#[derive(Debug, Clone, Copy)]
634#[repr(transparent)]
635pub struct SFrameFDEInfo2(u8);
636
637impl SFrameFDEInfo2 {
638 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
640 let fdetype = self.0 & 0b11111;
641 match fdetype {
642 0 => Ok(SFrameFDEType::Default),
643 1 => Ok(SFrameFDEType::Flex),
644 _ => Err(SFrameError::UnsupportedFDEType),
645 }
646 }
647}
648
649#[derive(Debug, Clone, Copy)]
653pub enum SFrameFREType {
654 Addr1,
658 Addr2,
662 Addr4,
666}
667
668#[derive(Debug, Clone, Copy)]
672pub enum SFrameFDEPCType {
673 PCInc,
675 PCMask,
677}
678
679#[derive(Debug, Clone, Copy)]
683pub enum SFrameFDEType {
684 Default,
694
695 Flex,
705}
706
707#[derive(Debug, Clone, Copy)]
711pub enum SFrameAArch64PAuthKey {
712 KeyA,
714 KeyB,
716}
717
718#[derive(Debug, Clone, Copy)]
722pub struct SFrameFDE {
723 offset: usize,
725 pub func_start_offset: i64,
732 pub func_size: u32,
735 pub func_start_fre_off: u32,
739 pub func_num_fres: u16,
742 pub func_info: SFrameFDEInfo,
745 pub func_info2: SFrameFDEInfo2,
747 pub func_rep_size: u8,
751}
752
753impl SFrameFDE {
754 pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
756 self.func_info2.get_fde_type()
757 }
758
759 pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
761 if section
767 .flags
768 .contains(SFrameFlags::SFRAME_F_FDE_FUNC_START_PCREL)
769 {
770 self.func_start_offset
771 .wrapping_add_unsigned(self.offset as u64)
772 .wrapping_add_unsigned(section.section_base) as u64
773 } else {
774 self.func_start_offset
775 .wrapping_add_unsigned(section.section_base) as u64
776 }
777 }
778
779 pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
781 let offset = section.freoff as usize
790 + core::mem::size_of::<RawSFrameHeader>()
791 + self.func_start_fre_off as usize
792 + core::mem::size_of::<RawSFrameFDEAttr>();
793 SFrameFREIterator {
794 fde: self,
795 section,
796 offset,
797 index: 0,
798 }
799 }
800
801 pub fn find_fre(
803 &self,
804 section: &SFrameSection<'_>,
805 pc: u64,
806 ) -> SFrameResult<Option<SFrameFRE>> {
807 let fde_pc = self.get_pc(section);
808 if pc < fde_pc || pc - fde_pc >= self.func_size as u64 {
809 return Ok(None);
811 }
812
813 match self.func_info.get_fde_pctype()? {
814 SFrameFDEPCType::PCInc => {
815 let mut last: Option<SFrameFRE> = None;
817 let mut iter = self.iter_fre(section);
818 while let Some(fre) = iter.next()? {
819 if fre.start_address.get() as u64 + fde_pc > pc {
820 break;
822 }
823 last = Some(fre);
824 }
825 if let Some(fre) = last {
826 if fre.start_address.get() as u64 + fde_pc <= pc {
828 return Ok(Some(fre));
829 }
830 }
831 Ok(None)
832 }
833 SFrameFDEPCType::PCMask => {
834 let mut iter = self.iter_fre(section);
836 while let Some(fre) = iter.next()? {
837 if self.func_rep_size != 0
839 && pc % self.func_rep_size as u64 >= fre.start_address.get() as u64
840 {
841 return Ok(Some(fre));
843 }
844 }
845 Ok(None)
846 }
847 }
848 }
849}
850
851#[derive(Debug, Clone, Copy)]
855pub enum SFrameFREStartAddress {
856 U8(u8),
857 U16(u16),
858 U32(u32),
859}
860
861impl SFrameFREStartAddress {
862 pub fn get(&self) -> u32 {
864 match self {
865 SFrameFREStartAddress::U8(i) => *i as u32,
866 SFrameFREStartAddress::U16(i) => *i as u32,
867 SFrameFREStartAddress::U32(i) => *i,
868 }
869 }
870}
871
872#[derive(Debug, Clone, Copy)]
876pub enum SFrameFREStackOffset {
877 I8(i8),
878 I16(i16),
879 I32(i32),
880}
881
882impl SFrameFREStackOffset {
883 pub fn get(&self) -> i32 {
885 match self {
886 SFrameFREStackOffset::I8(i) => *i as i32,
887 SFrameFREStackOffset::I16(i) => *i as i32,
888 SFrameFREStackOffset::I32(i) => *i,
889 }
890 }
891}
892
893#[derive(Debug, Clone)]
897pub struct SFrameFRE {
898 pub start_address: SFrameFREStartAddress,
900 pub info: SFrameFREInfo,
902 pub stack_offsets: Vec<SFrameFREStackOffset>,
904}
905
906#[derive(Debug, Clone, Copy)]
914pub struct SFrameFlexControlData {
915 value: i32,
917}
918
919impl SFrameFlexControlData {
920 pub fn new(value: i32) -> Self {
922 Self { value }
923 }
924
925 pub fn is_padding(&self) -> bool {
930 self.value == 0
931 }
932
933 pub fn reg_p(&self) -> bool {
938 (self.value & 0b1) != 0
939 }
940
941 pub fn deref_p(&self) -> bool {
947 (self.value & 0b10) != 0
948 }
949
950 pub fn regnum(&self) -> i32 {
954 self.value >> 3
955 }
956}
957
958#[derive(Debug, Clone, Copy)]
963pub struct SFrameFlexRecoveryRule {
964 pub control: SFrameFlexControlData,
966 pub offset: i32,
968}
969
970impl SFrameFRE {
971 pub fn get_cfa_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
973 self.stack_offsets.first().map(|offset| {
974 let offset = offset.get();
975 match section.abi {
976 SFrameABI::S390XBigEndian => s390x::cfa_offset_decode(offset),
978 _ => offset,
979 }
980 })
981 }
982
983 pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
990 match section.abi {
991 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
993 self.stack_offsets.get(1).map(|offset| offset.get())
994 }
995 SFrameABI::AMD64LittleEndian => Some(section.cfa_fixed_ra_offset as i32),
997 SFrameABI::S390XBigEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
999 }
1000 }
1001
1002 pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
1008 match section.abi {
1009 SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
1011 self.stack_offsets.get(2).map(|offset| offset.get())
1012 }
1013 SFrameABI::AMD64LittleEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
1015 SFrameABI::S390XBigEndian => self.stack_offsets.get(2).map(|offset| offset.get()),
1017 }
1018 }
1019
1020 pub fn get_flex_recovery_rules(&self) -> Option<SFrameFlexRecoveryRules> {
1027 let data_words: Vec<i32> = self.stack_offsets.iter().map(|o| o.get()).collect();
1028
1029 let cfa_control = SFrameFlexControlData::new(*data_words.get(0)?);
1031 let cfa_offset = *data_words.get(1)?;
1032 let cfa = SFrameFlexRecoveryRule {
1033 control: cfa_control,
1034 offset: cfa_offset,
1035 };
1036
1037 let mut offset = 2;
1039 let mut ra = None;
1040 if data_words.len() >= 3 {
1041 let ra_control = SFrameFlexControlData::new(*data_words.get(2)?);
1042 if ra_control.is_padding() {
1043 ra = Some(SFrameFlexRecoveryRule {
1044 control: ra_control,
1045 offset: 0,
1046 });
1047 offset += 1;
1048 } else {
1049 ra = Some(SFrameFlexRecoveryRule {
1050 control: ra_control,
1051 offset: *data_words.get(3)?,
1052 });
1053 offset += 2;
1054 }
1055 }
1056
1057 let mut fp = None;
1059 if data_words.len() >= offset + 1 {
1060 let fp_control = SFrameFlexControlData::new(*data_words.get(offset)?);
1061 if fp_control.is_padding() {
1062 fp = Some(SFrameFlexRecoveryRule {
1063 control: fp_control,
1064 offset: 0,
1065 });
1066 } else {
1067 fp = Some(SFrameFlexRecoveryRule {
1068 control: fp_control,
1069 offset: *data_words.get(offset + 1)?,
1070 });
1071 }
1072 }
1073
1074 Some(SFrameFlexRecoveryRules { cfa, ra, fp })
1075 }
1076}
1077
1078#[derive(Debug, Clone)]
1080pub struct SFrameFlexRecoveryRules {
1081 pub cfa: SFrameFlexRecoveryRule,
1083 pub ra: Option<SFrameFlexRecoveryRule>,
1085 pub fp: Option<SFrameFlexRecoveryRule>,
1087}
1088
1089#[derive(Debug, Clone, Copy)]
1093#[repr(transparent)]
1094pub struct SFrameFREInfo(u8);
1095
1096impl SFrameFREInfo {
1097 pub fn get_mangled_ra_p(&self) -> bool {
1100 (self.0 >> 7) & 0b1 == 1
1101 }
1102
1103 pub fn get_dataword_size(&self) -> SFrameResult<usize> {
1105 match (self.0 >> 5) & 0b11 {
1106 0x0 => Ok(1),
1108 0x1 => Ok(2),
1110 0x2 => Ok(4),
1112 _ => Err(SFrameError::UnsupportedFREDataWordSize),
1113 }
1114 }
1115
1116 pub fn get_dataword_count(&self) -> u8 {
1118 (self.0 >> 1) & 0b1111
1119 }
1120
1121 pub fn get_cfa_base_reg_id(&self) -> u8 {
1123 self.0 & 0b1
1124 }
1125}
1126
1127pub struct SFrameFREIterator<'a> {
1129 fde: &'a SFrameFDE,
1130 section: &'a SFrameSection<'a>,
1131 index: u16,
1132 offset: usize,
1133}
1134
1135impl<'a> FallibleIterator for SFrameFREIterator<'a> {
1136 type Item = SFrameFRE;
1137 type Error = SFrameError;
1138
1139 fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
1140 if self.index >= self.fde.func_num_fres {
1141 return Ok(None);
1142 }
1143
1144 let fre_type = self.fde.func_info.get_fre_type()?;
1145 let entry_size = match fre_type {
1146 SFrameFREType::Addr1 => 1 + 1,
1147 SFrameFREType::Addr2 => 2 + 1,
1148 SFrameFREType::Addr4 => 4 + 1,
1149 } as usize;
1150 let offset = self.offset;
1151 if offset + entry_size > self.section.data.len() {
1152 return Err(SFrameError::UnexpectedEndOfData);
1153 }
1154
1155 let (start_address, info) = match self.fde.func_info.get_fre_type()? {
1156 SFrameFREType::Addr1 => (
1157 SFrameFREStartAddress::U8(self.section.data[offset]),
1158 SFrameFREInfo(self.section.data[offset + 1]),
1159 ),
1160 SFrameFREType::Addr2 => (
1161 SFrameFREStartAddress::U16(read_binary!(
1162 self.section.data,
1163 self.section.little_endian,
1164 u16,
1165 offset
1166 )),
1167 SFrameFREInfo(self.section.data[offset + 2]),
1168 ),
1169 SFrameFREType::Addr4 => (
1170 SFrameFREStartAddress::U32(read_binary!(
1171 self.section.data,
1172 self.section.little_endian,
1173 u32,
1174 offset
1175 )),
1176 SFrameFREInfo(self.section.data[offset + 4]),
1177 ),
1178 };
1179
1180 let offset_size = info.get_dataword_size()?;
1181 let offset_count = info.get_dataword_count() as usize;
1182 let offset_total_size = offset_size * offset_count;
1183 if offset + entry_size + offset_total_size > self.section.data.len() {
1184 return Err(SFrameError::UnexpectedEndOfData);
1185 }
1186
1187 let mut stack_offsets = vec![];
1188 for i in 0..offset_count {
1189 match offset_size {
1190 1 => stack_offsets.push(SFrameFREStackOffset::I8(
1191 self.section.data[offset + entry_size + i * offset_size] as i8,
1192 )),
1193 2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
1194 self.section.data,
1195 self.section.little_endian,
1196 i16,
1197 offset + entry_size + i * offset_size
1198 ))),
1199 4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
1200 self.section.data,
1201 self.section.little_endian,
1202 i32,
1203 offset + entry_size + i * offset_size
1204 ))),
1205 _ => unreachable!(),
1206 }
1207 }
1208
1209 self.offset += entry_size + offset_total_size;
1210 self.index += 1;
1211
1212 Ok(Some(SFrameFRE {
1213 start_address,
1214 info,
1215 stack_offsets,
1216 }))
1217 }
1218}
1219
1220pub struct SFrameFDEIterator<'a> {
1222 section: &'a SFrameSection<'a>,
1223 index: u32,
1224}
1225
1226impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
1227 type Item = SFrameFDE;
1228 type Error = SFrameError;
1229
1230 fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
1231 let res = self.section.get_fde(self.index);
1232 if let Ok(Some(_)) = res {
1233 self.index += 1;
1234 }
1235 res
1236 }
1237}