use crate::{
swift::{
SwiftRuntime,
context::{MethodDescriptorFlags, SwiftMethodKind},
},
util::{read_i32_le_at, read_u32_le_at, relative_pointer},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VTableEntry {
pub address: u64,
pub flags: MethodDescriptorFlags,
pub impl_va: u64,
}
impl VTableEntry {
pub fn kind(self) -> SwiftMethodKind {
self.flags.kind()
}
pub fn is_instance(self) -> bool {
self.flags.is_instance()
}
}
pub struct VTableIter<'a, 'p> {
pub(crate) rt: &'p SwiftRuntime<'a>,
pub(crate) base_va: u64,
pub(crate) count: u32,
pub(crate) cursor: u32,
}
impl<'a, 'p> VTableIter<'a, 'p> {
#[allow(dead_code)] pub(crate) fn empty(rt: &'p SwiftRuntime<'a>) -> Self {
Self {
rt,
base_va: 0,
count: 0,
cursor: 0,
}
}
}
impl<'a, 'p> Iterator for VTableIter<'a, 'p> {
type Item = VTableEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.count {
return None;
}
let i = self.cursor;
self.cursor = self.cursor.checked_add(1)?;
let entry_off = u64::from(i).checked_mul(8)?;
let entry_va = self.base_va.checked_add(entry_off)?;
let bytes = self.rt.read_bytes(entry_va, 8)?;
let flags_raw = read_u32_le_at(bytes, 0)?;
let impl_rel = read_i32_le_at(bytes, 4)?;
let impl_slot_va = entry_va.checked_add(4)?;
let impl_va = if impl_rel == 0 {
0
} else {
relative_pointer(impl_slot_va, impl_rel)
};
Some(VTableEntry {
address: entry_va,
flags: MethodDescriptorFlags(flags_raw),
impl_va,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OverrideEntry {
pub address: u64,
pub class_va: u64,
pub method_va: u64,
pub impl_va: u64,
}
pub struct OverrideEntryIter<'a, 'p> {
pub(crate) rt: &'p SwiftRuntime<'a>,
pub(crate) base_va: u64,
pub(crate) count: u32,
pub(crate) cursor: u32,
}
impl<'a, 'p> OverrideEntryIter<'a, 'p> {
#[allow(dead_code)] pub(crate) fn empty(rt: &'p SwiftRuntime<'a>) -> Self {
Self {
rt,
base_va: 0,
count: 0,
cursor: 0,
}
}
}
impl<'a, 'p> Iterator for OverrideEntryIter<'a, 'p> {
type Item = OverrideEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.count {
return None;
}
let i = self.cursor;
self.cursor = self.cursor.checked_add(1)?;
let entry_off = u64::from(i).checked_mul(12)?;
let entry_va = self.base_va.checked_add(entry_off)?;
let bytes = self.rt.read_bytes(entry_va, 12)?;
let class_rel = read_i32_le_at(bytes, 0)?;
let method_rel = read_i32_le_at(bytes, 4)?;
let impl_rel = read_i32_le_at(bytes, 8)?;
let class_va = if class_rel == 0 {
0
} else {
relative_pointer(entry_va, class_rel)
};
let method_slot_va = entry_va.checked_add(4)?;
let method_va = if method_rel == 0 {
0
} else {
relative_pointer(method_slot_va, method_rel)
};
let impl_slot_va = entry_va.checked_add(8)?;
let impl_va = if impl_rel == 0 {
0
} else {
relative_pointer(impl_slot_va, impl_rel)
};
Some(OverrideEntry {
address: entry_va,
class_va,
method_va,
impl_va,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DefaultOverrideEntry {
pub address: u64,
pub method_va: u64,
pub impl_va: u64,
}
pub struct DefaultOverrideEntryIter<'a, 'p> {
pub(crate) rt: &'p SwiftRuntime<'a>,
pub(crate) base_va: u64,
pub(crate) count: u32,
pub(crate) cursor: u32,
}
impl<'a, 'p> DefaultOverrideEntryIter<'a, 'p> {
#[allow(dead_code)] pub(crate) fn empty(rt: &'p SwiftRuntime<'a>) -> Self {
Self {
rt,
base_va: 0,
count: 0,
cursor: 0,
}
}
}
impl<'a, 'p> Iterator for DefaultOverrideEntryIter<'a, 'p> {
type Item = DefaultOverrideEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.count {
return None;
}
let i = self.cursor;
self.cursor = self.cursor.checked_add(1)?;
let entry_off = u64::from(i).checked_mul(8)?;
let entry_va = self.base_va.checked_add(entry_off)?;
let bytes = self.rt.read_bytes(entry_va, 8)?;
let method_rel = read_i32_le_at(bytes, 0)?;
let impl_rel = read_i32_le_at(bytes, 4)?;
let method_va = if method_rel == 0 {
0
} else {
relative_pointer(entry_va, method_rel)
};
let impl_slot_va = entry_va.checked_add(4)?;
let impl_va = if impl_rel == 0 {
0
} else {
relative_pointer(impl_slot_va, impl_rel)
};
Some(DefaultOverrideEntry {
address: entry_va,
method_va,
impl_va,
})
}
}