use crate::{swift::SwiftRuntime, util::read_u32_le_at};
const CAPTURE_HEADER_SIZE: u64 = 12;
const CAPTURE_TYPE_RECORD_SIZE: u64 = 4;
const METADATA_SOURCE_RECORD_SIZE: u64 = 8;
#[derive(Debug, Clone)]
pub struct CaptureDescriptor {
pub address: u64,
pub num_capture_types: u32,
pub num_metadata_sources: u32,
pub num_bindings: u32,
}
impl CaptureDescriptor {
pub fn capture_types_address(&self) -> u64 {
self.address.wrapping_add(CAPTURE_HEADER_SIZE)
}
pub fn metadata_sources_address(&self) -> u64 {
self.capture_types_address()
.wrapping_add(u64::from(self.num_capture_types).wrapping_mul(CAPTURE_TYPE_RECORD_SIZE))
}
pub fn bindings_address(&self) -> u64 {
self.metadata_sources_address().wrapping_add(
u64::from(self.num_metadata_sources).wrapping_mul(METADATA_SOURCE_RECORD_SIZE),
)
}
}
pub struct CaptureIter<'a, 'p> {
rt: &'p SwiftRuntime<'a>,
cursor: usize,
}
impl<'a, 'p> CaptureIter<'a, 'p> {
pub(crate) fn new(rt: &'p SwiftRuntime<'a>) -> Self {
Self { rt, cursor: 0 }
}
}
impl<'a, 'p> Iterator for CaptureIter<'a, 'p> {
type Item = CaptureDescriptor;
fn next(&mut self) -> Option<Self::Item> {
let section = self.rt.capture.as_ref()?;
let start_off = self.cursor;
let header_end = start_off.checked_add(CAPTURE_HEADER_SIZE as usize)?;
if header_end > section.body.len() {
return None;
}
let header = section.body.get(start_off..header_end)?;
let num_capture_types = read_u32_le_at(header, 0)?;
let num_metadata_sources = read_u32_le_at(header, 4)?;
let num_bindings = read_u32_le_at(header, 8)?;
let after_captures = u64::from(num_capture_types)
.checked_mul(CAPTURE_TYPE_RECORD_SIZE)
.and_then(|n| n.checked_add(CAPTURE_HEADER_SIZE))?;
let after_sources = u64::from(num_metadata_sources)
.checked_mul(METADATA_SOURCE_RECORD_SIZE)
.and_then(|n| n.checked_add(after_captures))?;
let next_off_offset = usize::try_from(after_sources).ok()?;
let next_off = start_off.checked_add(next_off_offset)?;
let descriptor_va = section.vmaddr.wrapping_add(start_off as u64);
self.cursor = if num_bindings != 0 {
section.body.len()
} else if next_off > section.body.len() {
section.body.len()
} else {
next_off
};
Some(CaptureDescriptor {
address: descriptor_va,
num_capture_types,
num_metadata_sources,
num_bindings,
})
}
}