use crate::{
swift::SwiftRuntime,
util::{read_i32_le_at, read_u32_le_at, relative_pointer},
};
#[derive(Debug, Clone)]
pub struct DynamicReplacementScope {
pub address: u64,
pub scope_va: u64,
pub flags: u32,
}
pub struct ReplacementIter<'a, 'p> {
rt: &'p SwiftRuntime<'a>,
cursor: usize,
total: u32,
consumed: u32,
header_done: bool,
}
impl<'a, 'p> ReplacementIter<'a, 'p> {
pub(crate) fn new(rt: &'p SwiftRuntime<'a>) -> Self {
Self {
rt,
cursor: 0,
total: 0,
consumed: 0,
header_done: false,
}
}
}
impl<'a, 'p> Iterator for ReplacementIter<'a, 'p> {
type Item = DynamicReplacementScope;
fn next(&mut self) -> Option<Self::Item> {
let section = self.rt.replac.as_ref()?;
if !self.header_done {
let header = section.body.get(0..8)?;
let num_scopes = read_u32_le_at(header, 4)?;
self.total = num_scopes;
self.cursor = 8;
self.header_done = true;
}
if self.consumed >= self.total {
return None;
}
let entry_off = self.cursor;
let entry_end = entry_off.checked_add(8)?;
if entry_end > section.body.len() {
return None;
}
let bytes = section.body.get(entry_off..entry_end)?;
let scope_rel = read_i32_le_at(bytes, 0)?;
let flags = read_u32_le_at(bytes, 4)?;
self.cursor = entry_end;
self.consumed = self.consumed.checked_add(1)?;
let entry_va = section.vmaddr.wrapping_add(entry_off as u64);
let scope_va = if scope_rel == 0 {
0
} else {
relative_pointer(entry_va, scope_rel)
};
Some(DynamicReplacementScope {
address: entry_va,
scope_va,
flags,
})
}
}