use std::sync::Arc;
use tracing::{info, warn};
use crate::dyld::DyldContext;
use crate::error::Result;
use crate::macho::MachOContext;
pub const EXTRA_SEGMENT_NAME: &str = "__EXTRA_OBJC";
#[derive(Debug)]
pub struct ExtractionContext {
pub cache: Arc<DyldContext>,
pub macho: MachOContext,
pub extra_segment_data: Vec<u8>,
pub has_redacted_indirect: bool,
pub image_path: String,
pub image_address: u64,
pub verbosity: u8,
}
impl ExtractionContext {
pub fn new(
cache: Arc<DyldContext>,
macho: MachOContext,
image_path: String,
image_address: u64,
) -> Self {
Self {
cache,
macho,
extra_segment_data: Vec::new(),
has_redacted_indirect: false,
image_path,
image_address,
verbosity: 1,
}
}
pub fn with_verbosity(mut self, verbosity: u8) -> Self {
self.verbosity = verbosity;
self
}
pub fn is_arm64e(&self) -> bool {
self.macho.is_arm64e()
}
pub fn image_name(&self) -> &str {
self.image_path
.rsplit('/')
.next()
.unwrap_or(&self.image_path)
}
pub fn warn(&self, message: &str) {
if self.verbosity >= 1 {
warn!("{}: {}", self.image_name(), message);
}
}
pub fn info(&self, message: &str) {
if self.verbosity >= 2 {
info!("{}: {}", self.image_name(), message);
}
}
pub fn read_cache_at(&self, addr: u64, len: usize) -> Result<&[u8]> {
self.cache.data_at_addr(addr, len)
}
pub fn cache_addr_to_macho_offset(&self, addr: u64) -> Option<usize> {
self.macho.addr_to_offset(addr)
}
pub fn add_to_extra_segment(&mut self, data: &[u8]) -> u64 {
let offset = self.extra_segment_data.len();
self.extra_segment_data.extend_from_slice(data);
offset as u64
}
pub fn extra_segment_size(&self) -> usize {
self.extra_segment_data.len()
}
pub fn has_extra_segment(&self) -> bool {
!self.extra_segment_data.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct WriteProcedure {
pub write_offset: u64,
pub read_offset: u64,
pub size: u64,
pub source: WriteSource,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)] pub enum WriteSource {
Cache {
subcache_index: usize,
},
Macho,
ExtraSegment,
}
impl WriteProcedure {
pub fn from_cache(
write_offset: u64,
read_offset: u64,
size: u64,
subcache_index: usize,
) -> Self {
Self {
write_offset,
read_offset,
size,
source: WriteSource::Cache { subcache_index },
}
}
pub fn from_macho(write_offset: u64, read_offset: u64, size: u64) -> Self {
Self {
write_offset,
read_offset,
size,
source: WriteSource::Macho,
}
}
pub fn from_extra(write_offset: u64, read_offset: u64, size: u64) -> Self {
Self {
write_offset,
read_offset,
size,
source: WriteSource::ExtraSegment,
}
}
}