use std::{cmp::Ordering, fmt::Write};
use bitflags::bitflags;
use fallible_iterator::FallibleIterator;
use crate::{SFrameError, SFrameResult, read_binary, read_struct};
#[derive(Debug, Clone, Copy)]
pub enum SFrameABI {
AArch64BigEndian,
AArch64LittleEndian,
AMD64LittleEndian,
S390XBigEndian,
}
pub mod s390x {
pub const SFRAME_S390X_SP_VAL_OFFSET: i32 = -160;
pub const SFRAME_S390X_CFA_OFFSET_ADJUSTMENT: i32 = SFRAME_S390X_SP_VAL_OFFSET;
pub const SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR: i32 = 8;
pub const SFRAME_FRE_RA_OFFSET_INVALID: i32 = 0;
pub const fn cfa_offset_decode(offset: i32) -> i32 {
(offset * SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR) - SFRAME_S390X_CFA_OFFSET_ADJUSTMENT
}
pub const fn offset_is_regnum(offset: i32) -> bool {
(offset & 1) != 0
}
pub const fn offset_decode_regnum(offset: i32) -> i32 {
offset >> 1
}
}
bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct SFrameFlags: u8 {
const SFRAME_F_FDE_SORTED = 0x1;
const SFRAME_F_FRAME_POINTER = 0x2;
const SFRAME_F_FDE_FUNC_START_PCREL = 0x4;
}
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct SFrameSection<'a> {
data: &'a [u8],
section_base: u64,
little_endian: bool,
flags: SFrameFlags,
abi: SFrameABI,
cfa_fixed_fp_offset: i8,
cfa_fixed_ra_offset: i8,
auxhdr_len: u8,
num_fdes: u32,
num_fres: u32,
fre_len: u32,
fdeoff: u32,
freoff: u32,
}
const SFRAME_MAGIC: u16 = 0xdee2;
fn get_regname_from_dwarf(regnum: i32, abi: SFrameABI) -> String {
match (regnum, abi) {
(6, SFrameABI::AMD64LittleEndian) => "fp".to_string(),
(7, SFrameABI::AMD64LittleEndian) => "sp".to_string(),
_ => format!("r{}", regnum),
}
}
fn flex_recovery_rule_to_string(rule: &SFrameFlexRecoveryRule, abi: SFrameABI) -> String {
match (
rule.control.is_padding(),
rule.control.reg_p(),
rule.control.deref_p(),
) {
(true, _, _) => {
format!("U")
}
(false, true, true) => {
format!(
"({}{:+})",
get_regname_from_dwarf(rule.control.regnum(), abi),
rule.offset
)
}
(false, true, false) => {
format!(
"{}{:+}",
get_regname_from_dwarf(rule.control.regnum(), abi),
rule.offset
)
}
(false, false, _) => {
format!("c{:+}", rule.offset)
}
}
}
impl<'a> SFrameSection<'a> {
pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
if data.len() < core::mem::size_of::<RawSFrameHeader>() {
return Err(SFrameError::UnexpectedEndOfData);
}
let magic_offset = core::mem::offset_of!(RawSFrameHeader, magic);
let mut magic_bytes: [u8; 2] = [0; 2];
magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
let magic_le = u16::from_le_bytes(magic_bytes);
let little_endian;
if magic_le == SFRAME_MAGIC {
little_endian = true;
} else {
let magic_be = u16::from_be_bytes(magic_bytes);
if magic_be == SFRAME_MAGIC {
little_endian = false;
} else {
return Err(SFrameError::InvalidMagic);
}
}
let version_offset = core::mem::offset_of!(RawSFrameHeader, version);
let version = data[version_offset];
if version != 3 {
return Err(SFrameError::UnsupportedVersion);
}
let flags_offset = core::mem::offset_of!(RawSFrameHeader, flags);
let flags = data[flags_offset];
let flags = match SFrameFlags::from_bits(flags) {
Some(flags) => flags,
None => return Err(SFrameError::UnsupportedFlags),
};
let abi_offset = core::mem::offset_of!(RawSFrameHeader, abi_arch);
let abi = data[abi_offset];
let abi = match abi {
1 => SFrameABI::AArch64BigEndian,
2 => SFrameABI::AArch64LittleEndian,
3 => SFrameABI::AMD64LittleEndian,
4 => SFrameABI::S390XBigEndian,
_ => return Err(SFrameError::UnsupportedABI),
};
let cfa_fixed_fp_offset =
data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_fp_offset)] as i8;
let cfa_fixed_ra_offset =
data[core::mem::offset_of!(RawSFrameHeader, cfa_fixed_ra_offset)] as i8;
let auxhdr_len = data[core::mem::offset_of!(RawSFrameHeader, auxhdr_len)];
let num_fdes = read_struct!(RawSFrameHeader, data, little_endian, num_fdes, u32);
let fdeoff = read_struct!(RawSFrameHeader, data, little_endian, fdeoff, u32);
if data.len() - core::mem::size_of::<RawSFrameHeader>() < fdeoff as usize {
return Err(SFrameError::UnexpectedEndOfData);
} else if (data.len() - core::mem::size_of::<RawSFrameHeader>() - fdeoff as usize)
/ core::mem::size_of::<RawSFrameFDEIndex>()
< num_fdes as usize
{
return Err(SFrameError::UnexpectedEndOfData);
}
Ok(SFrameSection {
data,
section_base,
little_endian,
flags,
abi,
cfa_fixed_fp_offset,
cfa_fixed_ra_offset,
auxhdr_len,
num_fdes,
num_fres: read_struct!(RawSFrameHeader, data, little_endian, num_fres, u32),
fre_len: read_struct!(RawSFrameHeader, data, little_endian, fre_len, u32),
fdeoff,
freoff: read_struct!(RawSFrameHeader, data, little_endian, freoff, u32),
})
}
pub fn get_fde_count(&self) -> u32 {
self.num_fdes
}
pub fn get_fde(&self, index: u32) -> SFrameResult<Option<SFrameFDE>> {
if index >= self.num_fdes {
return Ok(None);
}
let offset = self.fdeoff as usize
+ index as usize * core::mem::size_of::<RawSFrameFDEIndex>()
+ core::mem::size_of::<RawSFrameHeader>();
if offset + core::mem::size_of::<RawSFrameFDEIndex>() > self.data.len() {
return Err(SFrameError::UnexpectedEndOfData);
}
let func_start_fre_off = read_struct!(
RawSFrameFDEIndex,
&self.data[offset..],
self.little_endian,
func_start_fre_off,
u32
);
let fre_offset = self.freoff as usize
+ core::mem::size_of::<RawSFrameHeader>()
+ func_start_fre_off as usize;
let func_num_fres = read_struct!(
RawSFrameFDEAttr,
&self.data[fre_offset..],
self.little_endian,
func_num_fres,
u16
);
let func_info = read_struct!(
RawSFrameFDEAttr,
&self.data[fre_offset..],
self.little_endian,
func_info,
u8
);
let func_info2 = read_struct!(
RawSFrameFDEAttr,
&self.data[fre_offset..],
self.little_endian,
func_info2,
u8
);
let func_rep_size = read_struct!(
RawSFrameFDEAttr,
&self.data[fre_offset..],
self.little_endian,
func_rep_size,
u8
);
Ok(Some(SFrameFDE {
offset,
func_start_offset: read_struct!(
RawSFrameFDEIndex,
&self.data[offset..],
self.little_endian,
func_start_offset,
i64
),
func_size: read_struct!(
RawSFrameFDEIndex,
&self.data[offset..],
self.little_endian,
func_size,
u32
),
func_start_fre_off,
func_num_fres,
func_info: SFrameFDEInfo(func_info),
func_info2: SFrameFDEInfo2(func_info2),
func_rep_size,
}))
}
pub fn to_string(&self) -> SFrameResult<String> {
let mut s = String::new();
writeln!(&mut s, "Header :")?;
writeln!(&mut s)?;
writeln!(&mut s, " Version: SFRAME_VERSION_3")?;
writeln!(
&mut s,
" Flags: {}",
self.flags
.iter_names()
.map(|(name, _flag)| name)
.collect::<Vec<_>>()
.join(",\n ")
)?;
if self.cfa_fixed_fp_offset != 0 {
writeln!(
&mut s,
" CFA fixed FP offset: {:?}",
self.cfa_fixed_fp_offset
)?;
}
if self.cfa_fixed_ra_offset != 0 {
writeln!(
&mut s,
" CFA fixed RA offset: {:?}",
self.cfa_fixed_ra_offset
)?;
}
writeln!(&mut s, " Num FDEs: {:?}", self.num_fdes)?;
writeln!(&mut s, " Num FREs: {:?}", self.num_fres)?;
writeln!(&mut s)?;
writeln!(&mut s, "Function Index :")?;
writeln!(&mut s)?;
for i in 0..self.num_fdes {
let fde = self.get_fde(i)?.unwrap();
let pc = fde.get_pc(self);
let mut suffix = String::new();
let mut attrs = "".to_string();
if fde.func_info.is_signal_frame()? {
attrs.push('S');
}
if let Ok(SFrameFDEType::Flex) = fde.func_info2.get_fde_type() {
attrs.push('F');
}
if !attrs.is_empty() {
suffix += &format!(", attr = \"{}\"", attrs);
};
if let SFrameAArch64PAuthKey::KeyB = fde.func_info.get_aarch64_pauth_key()? {
suffix += ", pauth = B key";
}
writeln!(
&mut s,
" func idx [{i}]: pc = 0x{:x}, size = {} bytes{}",
pc, fde.func_size, suffix
)?;
match fde.func_info.get_fde_pctype()? {
SFrameFDEPCType::PCInc => {
writeln!(&mut s, " STARTPC CFA FP RA")?;
}
SFrameFDEPCType::PCMask => {
writeln!(&mut s, " STARTPC[m] CFA FP RA")?;
}
}
let mut iter = fde.iter_fre(self);
while let Some(fre) = iter.next()? {
let start_pc = match fde.func_info.get_fde_pctype()? {
SFrameFDEPCType::PCInc => pc + fre.start_address.get() as u64,
SFrameFDEPCType::PCMask => fre.start_address.get() as u64,
};
match fde.func_info2.get_fde_type() {
Ok(SFrameFDEType::Default) => {
if fre.stack_offsets.is_empty() {
writeln!(&mut s, " {:016x} RA undefined", start_pc)?;
} else {
let base_reg = if fre.info.get_cfa_base_reg_id() == 0 {
"fp"
} else {
"sp"
};
let cfa = format!("{}+{}", base_reg, fre.stack_offsets[0].get());
let fp = match fre.get_fp_offset(self) {
Some(offset) => format!("c{:+}", offset),
None => "u".to_string(), };
let mut ra = if self.cfa_fixed_ra_offset != 0 {
"f".to_string() } else {
match fre.get_ra_offset(self) {
Some(offset) => format!("c{:+}", offset),
None => "u".to_string(), }
};
if fre.info.get_mangled_ra_p() {
ra.push_str("[s]");
}
let rest = format!("{cfa:8} {fp:6} {ra}");
writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
}
}
Ok(SFrameFDEType::Flex) => {
if let Some(rules) = fre.get_flex_recovery_rules() {
let cfa = flex_recovery_rule_to_string(&rules.cfa, self.abi);
let fp = if let Some(fp_rule) = rules.fp {
flex_recovery_rule_to_string(&fp_rule, self.abi)
} else {
"u".to_string()
};
let ra = if let Some(ra_rule) = rules.ra {
flex_recovery_rule_to_string(&ra_rule, self.abi)
} else {
if self.cfa_fixed_ra_offset != 0 {
"f".to_string()
} else {
"u".to_string()
}
};
let rest = format!("{cfa:8} {fp:6} {ra}");
writeln!(&mut s, " {:016x} {}", start_pc, rest)?;
} else {
writeln!(&mut s, " {:016x} RA undefined", start_pc)?;
}
}
_ => {}
}
}
writeln!(&mut s,)?;
}
Ok(s)
}
pub fn iter_fde(&self) -> SFrameFDEIterator<'_> {
SFrameFDEIterator {
section: self,
index: 0,
}
}
pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
if self.flags.contains(SFrameFlags::SFRAME_F_FDE_SORTED) {
let mut size = self.num_fdes;
if size == 0 {
return Ok(None);
}
let mut base = 0;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = self.get_fde(mid)?.unwrap().get_pc(self).cmp(&pc);
if cmp != Ordering::Greater {
base = mid;
}
size -= half;
}
let base_fde = self.get_fde(base)?.unwrap();
let base_pc = base_fde.get_pc(self);
let cmp = base_pc.cmp(&pc);
match cmp {
Ordering::Equal | Ordering::Less if pc < base_pc + base_fde.func_size as u64 => {
Ok(Some(base_fde))
}
_ => Ok(None),
}
} else {
let mut iter = self.iter_fde();
while let Some(fde) = iter.next()? {
let start = fde.get_pc(self);
if start <= pc && pc - start < fde.func_size as u64 {
return Ok(Some(fde));
}
}
Ok(None)
}
}
pub fn get_flags(&self) -> SFrameFlags {
self.flags
}
pub fn get_abi(&self) -> SFrameABI {
self.abi
}
pub fn get_cfa_fixed_fp_offset(&self) -> i8 {
self.cfa_fixed_fp_offset
}
pub fn get_cfa_fixed_ra_offset(&self) -> i8 {
self.cfa_fixed_ra_offset
}
}
#[repr(C, packed)]
struct RawSFrameHeader {
magic: u16,
version: u8,
flags: u8,
abi_arch: u8,
cfa_fixed_fp_offset: i8,
cfa_fixed_ra_offset: i8,
auxhdr_len: u8,
num_fdes: u32,
num_fres: u32,
fre_len: u32,
fdeoff: u32,
freoff: u32,
}
#[repr(C, packed)]
#[allow(dead_code)]
struct RawSFrameFDEIndex {
func_start_offset: i64,
func_size: u32,
func_start_fre_off: u32,
}
#[repr(C, packed)]
#[allow(dead_code)]
struct RawSFrameFDEAttr {
func_num_fres: u16,
func_info: u8,
func_info2: u8,
func_rep_size: u8,
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct SFrameFDEInfo(u8);
impl SFrameFDEInfo {
pub fn get_fre_type(&self) -> SFrameResult<SFrameFREType> {
let fretype = self.0 & 0b1111;
match fretype {
0 => Ok(SFrameFREType::Addr1),
1 => Ok(SFrameFREType::Addr2),
2 => Ok(SFrameFREType::Addr4),
_ => Err(SFrameError::UnsupportedFREType),
}
}
pub fn get_fde_pctype(&self) -> SFrameResult<SFrameFDEPCType> {
let fretype = (self.0 >> 4) & 0b1;
match fretype {
0 => Ok(SFrameFDEPCType::PCInc),
1 => Ok(SFrameFDEPCType::PCMask),
_ => unreachable!(),
}
}
pub fn get_aarch64_pauth_key(&self) -> SFrameResult<SFrameAArch64PAuthKey> {
let fretype = (self.0 >> 5) & 0b1;
match fretype {
0 => Ok(SFrameAArch64PAuthKey::KeyA),
1 => Ok(SFrameAArch64PAuthKey::KeyB),
_ => unreachable!(),
}
}
pub fn is_signal_frame(&self) -> SFrameResult<bool> {
let fretype = (self.0 >> 7) & 0b1;
match fretype {
0 => Ok(false),
1 => Ok(true),
_ => unreachable!(),
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct SFrameFDEInfo2(u8);
impl SFrameFDEInfo2 {
pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
let fdetype = self.0 & 0b11111;
match fdetype {
0 => Ok(SFrameFDEType::Default),
1 => Ok(SFrameFDEType::Flex),
_ => Err(SFrameError::UnsupportedFDEType),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameFREType {
Addr1,
Addr2,
Addr4,
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameFDEPCType {
PCInc,
PCMask,
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameFDEType {
Default,
Flex,
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameAArch64PAuthKey {
KeyA,
KeyB,
}
#[derive(Debug, Clone, Copy)]
pub struct SFrameFDE {
offset: usize,
pub func_start_offset: i64,
pub func_size: u32,
pub func_start_fre_off: u32,
pub func_num_fres: u16,
pub func_info: SFrameFDEInfo,
pub func_info2: SFrameFDEInfo2,
pub func_rep_size: u8,
}
impl SFrameFDE {
pub fn get_fde_type(&self) -> SFrameResult<SFrameFDEType> {
self.func_info2.get_fde_type()
}
pub fn get_pc(&self, section: &SFrameSection<'_>) -> u64 {
if section
.flags
.contains(SFrameFlags::SFRAME_F_FDE_FUNC_START_PCREL)
{
self.func_start_offset
.wrapping_add_unsigned(self.offset as u64)
.wrapping_add_unsigned(section.section_base) as u64
} else {
self.func_start_offset
.wrapping_add_unsigned(section.section_base) as u64
}
}
pub fn iter_fre<'a>(&'a self, section: &'a SFrameSection<'a>) -> SFrameFREIterator<'a> {
let offset = section.freoff as usize
+ core::mem::size_of::<RawSFrameHeader>()
+ self.func_start_fre_off as usize
+ core::mem::size_of::<RawSFrameFDEAttr>();
SFrameFREIterator {
fde: self,
section,
offset,
index: 0,
}
}
pub fn find_fre(
&self,
section: &SFrameSection<'_>,
pc: u64,
) -> SFrameResult<Option<SFrameFRE>> {
let fde_pc = self.get_pc(section);
if pc < fde_pc || pc - fde_pc >= self.func_size as u64 {
return Ok(None);
}
match self.func_info.get_fde_pctype()? {
SFrameFDEPCType::PCInc => {
let mut last: Option<SFrameFRE> = None;
let mut iter = self.iter_fre(section);
while let Some(fre) = iter.next()? {
if fre.start_address.get() as u64 + fde_pc > pc {
break;
}
last = Some(fre);
}
if let Some(fre) = last {
if fre.start_address.get() as u64 + fde_pc <= pc {
return Ok(Some(fre));
}
}
Ok(None)
}
SFrameFDEPCType::PCMask => {
let mut iter = self.iter_fre(section);
while let Some(fre) = iter.next()? {
if self.func_rep_size != 0
&& pc % self.func_rep_size as u64 >= fre.start_address.get() as u64
{
return Ok(Some(fre));
}
}
Ok(None)
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameFREStartAddress {
U8(u8),
U16(u16),
U32(u32),
}
impl SFrameFREStartAddress {
pub fn get(&self) -> u32 {
match self {
SFrameFREStartAddress::U8(i) => *i as u32,
SFrameFREStartAddress::U16(i) => *i as u32,
SFrameFREStartAddress::U32(i) => *i,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum SFrameFREStackOffset {
I8(i8),
I16(i16),
I32(i32),
}
impl SFrameFREStackOffset {
pub fn get(&self) -> i32 {
match self {
SFrameFREStackOffset::I8(i) => *i as i32,
SFrameFREStackOffset::I16(i) => *i as i32,
SFrameFREStackOffset::I32(i) => *i,
}
}
}
#[derive(Debug, Clone)]
pub struct SFrameFRE {
pub start_address: SFrameFREStartAddress,
pub info: SFrameFREInfo,
pub stack_offsets: Vec<SFrameFREStackOffset>,
}
#[derive(Debug, Clone, Copy)]
pub struct SFrameFlexControlData {
value: i32,
}
impl SFrameFlexControlData {
pub fn new(value: i32) -> Self {
Self { value }
}
pub fn is_padding(&self) -> bool {
self.value == 0
}
pub fn reg_p(&self) -> bool {
(self.value & 0b1) != 0
}
pub fn deref_p(&self) -> bool {
(self.value & 0b10) != 0
}
pub fn regnum(&self) -> i32 {
self.value >> 3
}
}
#[derive(Debug, Clone, Copy)]
pub struct SFrameFlexRecoveryRule {
pub control: SFrameFlexControlData,
pub offset: i32,
}
impl SFrameFRE {
pub fn get_cfa_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
self.stack_offsets.first().map(|offset| {
let offset = offset.get();
match section.abi {
SFrameABI::S390XBigEndian => s390x::cfa_offset_decode(offset),
_ => offset,
}
})
}
pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
match section.abi {
SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
self.stack_offsets.get(1).map(|offset| offset.get())
}
SFrameABI::AMD64LittleEndian => Some(section.cfa_fixed_ra_offset as i32),
SFrameABI::S390XBigEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
}
}
pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> Option<i32> {
match section.abi {
SFrameABI::AArch64BigEndian | SFrameABI::AArch64LittleEndian => {
self.stack_offsets.get(2).map(|offset| offset.get())
}
SFrameABI::AMD64LittleEndian => self.stack_offsets.get(1).map(|offset| offset.get()),
SFrameABI::S390XBigEndian => self.stack_offsets.get(2).map(|offset| offset.get()),
}
}
pub fn get_flex_recovery_rules(&self) -> Option<SFrameFlexRecoveryRules> {
let data_words: Vec<i32> = self.stack_offsets.iter().map(|o| o.get()).collect();
let cfa_control = SFrameFlexControlData::new(*data_words.get(0)?);
let cfa_offset = *data_words.get(1)?;
let cfa = SFrameFlexRecoveryRule {
control: cfa_control,
offset: cfa_offset,
};
let mut offset = 2;
let mut ra = None;
if data_words.len() >= 3 {
let ra_control = SFrameFlexControlData::new(*data_words.get(2)?);
if ra_control.is_padding() {
ra = Some(SFrameFlexRecoveryRule {
control: ra_control,
offset: 0,
});
offset += 1;
} else {
ra = Some(SFrameFlexRecoveryRule {
control: ra_control,
offset: *data_words.get(3)?,
});
offset += 2;
}
}
let mut fp = None;
if data_words.len() >= offset + 1 {
let fp_control = SFrameFlexControlData::new(*data_words.get(offset)?);
if fp_control.is_padding() {
fp = Some(SFrameFlexRecoveryRule {
control: fp_control,
offset: 0,
});
} else {
fp = Some(SFrameFlexRecoveryRule {
control: fp_control,
offset: *data_words.get(offset + 1)?,
});
}
}
Some(SFrameFlexRecoveryRules { cfa, ra, fp })
}
}
#[derive(Debug, Clone)]
pub struct SFrameFlexRecoveryRules {
pub cfa: SFrameFlexRecoveryRule,
pub ra: Option<SFrameFlexRecoveryRule>,
pub fp: Option<SFrameFlexRecoveryRule>,
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct SFrameFREInfo(u8);
impl SFrameFREInfo {
pub fn get_mangled_ra_p(&self) -> bool {
(self.0 >> 7) & 0b1 == 1
}
pub fn get_dataword_size(&self) -> SFrameResult<usize> {
match (self.0 >> 5) & 0b11 {
0x0 => Ok(1),
0x1 => Ok(2),
0x2 => Ok(4),
_ => Err(SFrameError::UnsupportedFREDataWordSize),
}
}
pub fn get_dataword_count(&self) -> u8 {
(self.0 >> 1) & 0b1111
}
pub fn get_cfa_base_reg_id(&self) -> u8 {
self.0 & 0b1
}
}
pub struct SFrameFREIterator<'a> {
fde: &'a SFrameFDE,
section: &'a SFrameSection<'a>,
index: u16,
offset: usize,
}
impl<'a> FallibleIterator for SFrameFREIterator<'a> {
type Item = SFrameFRE;
type Error = SFrameError;
fn next(&mut self) -> SFrameResult<Option<SFrameFRE>> {
if self.index >= self.fde.func_num_fres {
return Ok(None);
}
let fre_type = self.fde.func_info.get_fre_type()?;
let entry_size = match fre_type {
SFrameFREType::Addr1 => 1 + 1,
SFrameFREType::Addr2 => 2 + 1,
SFrameFREType::Addr4 => 4 + 1,
} as usize;
let offset = self.offset;
if offset + entry_size > self.section.data.len() {
return Err(SFrameError::UnexpectedEndOfData);
}
let (start_address, info) = match self.fde.func_info.get_fre_type()? {
SFrameFREType::Addr1 => (
SFrameFREStartAddress::U8(self.section.data[offset]),
SFrameFREInfo(self.section.data[offset + 1]),
),
SFrameFREType::Addr2 => (
SFrameFREStartAddress::U16(read_binary!(
self.section.data,
self.section.little_endian,
u16,
offset
)),
SFrameFREInfo(self.section.data[offset + 2]),
),
SFrameFREType::Addr4 => (
SFrameFREStartAddress::U32(read_binary!(
self.section.data,
self.section.little_endian,
u32,
offset
)),
SFrameFREInfo(self.section.data[offset + 4]),
),
};
let offset_size = info.get_dataword_size()?;
let offset_count = info.get_dataword_count() as usize;
let offset_total_size = offset_size * offset_count;
if offset + entry_size + offset_total_size > self.section.data.len() {
return Err(SFrameError::UnexpectedEndOfData);
}
let mut stack_offsets = vec![];
for i in 0..offset_count {
match offset_size {
1 => stack_offsets.push(SFrameFREStackOffset::I8(
self.section.data[offset + entry_size + i * offset_size] as i8,
)),
2 => stack_offsets.push(SFrameFREStackOffset::I16(read_binary!(
self.section.data,
self.section.little_endian,
i16,
offset + entry_size + i * offset_size
))),
4 => stack_offsets.push(SFrameFREStackOffset::I32(read_binary!(
self.section.data,
self.section.little_endian,
i32,
offset + entry_size + i * offset_size
))),
_ => unreachable!(),
}
}
self.offset += entry_size + offset_total_size;
self.index += 1;
Ok(Some(SFrameFRE {
start_address,
info,
stack_offsets,
}))
}
}
pub struct SFrameFDEIterator<'a> {
section: &'a SFrameSection<'a>,
index: u32,
}
impl<'a> FallibleIterator for SFrameFDEIterator<'a> {
type Item = SFrameFDE;
type Error = SFrameError;
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
let res = self.section.get_fde(self.index);
if let Ok(Some(_)) = res {
self.index += 1;
}
res
}
}