use num_traits::{Num, cast};
use std::mem::size_of;
use std::path::Path;
use std::pin::Pin;
use super::binding_info::BindingInfo;
use super::builder::Config;
use super::commands::atom_info::AtomInfo;
use super::commands::build_version::{BuildVersion, Platform};
use super::commands::code_signature::CodeSignature;
use super::commands::code_signature_dir::CodeSignatureDir;
use super::commands::data_in_code::DataInCode;
use super::commands::dyld_chained_fixups::DyldChainedFixups;
use super::commands::dyld_environment::DyldEnvironment;
use super::commands::dyld_export_trie::DyldExportsTrie;
use super::commands::dyldinfo::DyldInfo;
use super::commands::dylib::Libraries;
use super::commands::dylinker::Dylinker;
use super::commands::dynamic_symbol_command::DynamicSymbolCommand;
use super::commands::encryption_info::EncryptionInfo;
use super::commands::function_variant_fixups::FunctionVariantFixups;
use super::commands::function_variants::FunctionVariants;
use super::commands::functionstarts::FunctionStarts;
use super::commands::lazy_load_dylib_info::LazyLoadDylibInfo;
use super::commands::linker_opt_hint::LinkerOptHint;
use super::commands::main_cmd::Main;
use super::commands::note::Note;
use super::commands::routine::Routine;
use super::commands::rpath::RPath;
use super::commands::rpath::RPaths;
use super::commands::segment::{Segment, Segments};
use super::commands::segment_split_info::SegmentSplitInfo;
use super::commands::source_version::SourceVersion;
use super::commands::sub_client::SubClients;
use super::commands::sub_framework::SubFramework;
use super::commands::symbol_command::SymbolCommand;
use super::commands::thread_command::ThreadCommand;
use super::commands::two_level_hints::TwoLevelHints;
use super::commands::uuid::UUID;
use super::commands::version_min::VersionMin;
use super::commands::{Command, Commands, CommandsIter, Dylib, LoadCommandTypes};
use super::export_info::ExportInfo;
use super::header::Header;
use super::relocation::Relocations;
use super::section::{Section, Sections};
use super::stub::Stub;
use super::symbol::{ExportedSymbols, Symbol, Symbols};
use crate::Error;
use lief_ffi as ffi;
use crate::common::{AsFFI, FromFFI, into_optional};
use crate::objc::Metadata;
use crate::{declare_fwd_iterator, declare_iterator, generic, to_conv_result, to_result, to_slice};
pub struct Binary {
ptr: cxx::UniquePtr<ffi::MachO_Binary>,
}
impl std::fmt::Debug for Binary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Binary").finish()
}
}
impl FromFFI<ffi::MachO_Binary> for Binary {
fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Binary>) -> Self {
Binary { ptr }
}
}
impl Binary {
pub fn header(&self) -> Header<'_> {
Header::from_ffi(self.ptr.header())
}
pub fn commands(&self) -> CommandsIter<'_> {
CommandsIter::new(self.ptr.commands())
}
pub fn sections(&self) -> Sections<'_> {
Sections::new(self.ptr.sections())
}
pub fn segments(&self) -> Segments<'_> {
Segments::new(self.ptr.segments())
}
pub fn libraries(&self) -> Libraries<'_> {
Libraries::new(self.ptr.libraries())
}
pub fn relocations(&self) -> Relocations<'_> {
Relocations::new(self.ptr.relocations())
}
pub fn rpaths(&self) -> RPaths<'_> {
RPaths::new(self.ptr.rpaths())
}
pub fn symbols(&self) -> Symbols<'_> {
Symbols::new(self.ptr.symbols())
}
pub fn exported_symbols(&self) -> ExportedSymbols<'_> {
ExportedSymbols::new(self.ptr.exported_symbols())
}
pub fn dyld_info(&self) -> Option<DyldInfo<'_>> {
into_optional(self.ptr.dyld_info())
}
pub fn uuid(&self) -> Option<UUID<'_>> {
into_optional(self.ptr.uuid())
}
pub fn main_command(&self) -> Option<Main<'_>> {
into_optional(self.ptr.main_command())
}
pub fn dylinker(&self) -> Option<Dylinker<'_>> {
into_optional(self.ptr.dylinker())
}
pub fn function_starts(&self) -> Option<FunctionStarts<'_>> {
into_optional(self.ptr.function_starts())
}
pub fn source_version(&self) -> Option<SourceVersion<'_>> {
into_optional(self.ptr.source_version())
}
pub fn thread_command(&self) -> Option<ThreadCommand<'_>> {
into_optional(self.ptr.thread_command())
}
pub fn rpath(&self) -> Option<RPath<'_>> {
into_optional(self.ptr.rpath())
}
pub fn routine(&self) -> Option<Routine<'_>> {
into_optional(self.ptr.routine_command())
}
pub fn symbol_command(&self) -> Option<SymbolCommand<'_>> {
into_optional(self.ptr.symbol_command())
}
pub fn dynamic_symbol(&self) -> Option<DynamicSymbolCommand<'_>> {
into_optional(self.ptr.dynamic_symbol_command())
}
pub fn code_signature(&self) -> Option<CodeSignature<'_>> {
into_optional(self.ptr.code_signature())
}
pub fn code_signature_dir(&self) -> Option<CodeSignatureDir<'_>> {
into_optional(self.ptr.code_signature_dir())
}
pub fn data_in_code(&self) -> Option<DataInCode<'_>> {
into_optional(self.ptr.data_in_code())
}
pub fn segment_split_info(&self) -> Option<SegmentSplitInfo<'_>> {
into_optional(self.ptr.segment_split_info())
}
pub fn encryption_info(&self) -> Option<EncryptionInfo<'_>> {
into_optional(self.ptr.encryption_info())
}
pub fn sub_framework(&self) -> Option<SubFramework<'_>> {
into_optional(self.ptr.sub_framework())
}
pub fn subclients(&self) -> SubClients<'_> {
SubClients::new(self.ptr.subclients())
}
pub fn dyld_environment(&self) -> Option<DyldEnvironment<'_>> {
into_optional(self.ptr.dyld_environment())
}
pub fn build_version(&self) -> Option<BuildVersion<'_>> {
into_optional(self.ptr.build_version())
}
pub fn dyld_chained_fixups(&self) -> Option<DyldChainedFixups<'_>> {
into_optional(self.ptr.dyld_chained_fixups())
}
pub fn dyld_exports_trie(&self) -> Option<DyldExportsTrie<'_>> {
into_optional(self.ptr.dyld_exports_trie())
}
pub fn two_level_hints(&self) -> Option<TwoLevelHints<'_>> {
into_optional(self.ptr.two_level_hints())
}
pub fn linker_opt_hint(&self) -> Option<LinkerOptHint<'_>> {
into_optional(self.ptr.linker_opt_hint())
}
pub fn atom_info(&self) -> Option<AtomInfo<'_>> {
into_optional(self.ptr.atom_info())
}
pub fn function_variants(&self) -> Option<FunctionVariants<'_>> {
into_optional(self.ptr.function_variants())
}
pub fn function_variant_fixups(&self) -> Option<FunctionVariantFixups<'_>> {
into_optional(self.ptr.function_variant_fixups())
}
pub fn lazy_load_dylib_infos(&self) -> LazyLoadDylibInfos<'_> {
LazyLoadDylibInfos::new(self.ptr.lazy_load_dylib_infos())
}
pub fn version_min(&self) -> Option<VersionMin<'_>> {
into_optional(self.ptr.version_min())
}
pub fn support_arm64_ptr_auth(&self) -> bool {
self.ptr.support_arm64_ptr_auth()
}
pub fn bindings(&self) -> BindingsInfo<'_> {
BindingsInfo::new(self.ptr.bindings())
}
pub fn symbol_stubs(&self) -> Stubs<'_> {
Stubs::new(self.ptr.symbol_stubs())
}
pub fn objc_metadata(&self) -> Option<Metadata<'_>> {
into_optional(self.ptr.objc_metadata())
}
pub fn platform(&self) -> Platform {
Platform::from(self.ptr.platform())
}
pub fn is_ios(&self) -> bool {
self.ptr.is_ios()
}
pub fn is_macos(&self) -> bool {
self.ptr.is_macos()
}
pub fn find_library(&self, name: &str) -> Option<Dylib<'_>> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
into_optional(self.ptr.find_library(&__cxx_s))
}
pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
where
T: Num + cast::FromPrimitive + cast::ToPrimitive,
{
if size_of::<T>() == size_of::<u8>() {
to_conv_result!(
ffi::AbstractBinary::get_u8,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u16>() {
to_conv_result!(
ffi::AbstractBinary::get_u16,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u32>() {
to_conv_result!(
ffi::AbstractBinary::get_u32,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
if size_of::<T>() == size_of::<u64>() {
to_conv_result!(
ffi::AbstractBinary::get_u64,
self.ptr.as_ref().unwrap().as_ref(),
|value| {
T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
},
addr
);
}
Err(Error::NotSupported)
}
pub fn write<P: AsRef<Path>>(&mut self, output: P) {
cxx::let_cxx_string!(__cxx_s = output.as_ref().to_str().unwrap());
self.ptr.as_mut().unwrap().write(&__cxx_s);
}
pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
cxx::let_cxx_string!(__cxx_out = output.as_ref().to_str().unwrap());
let cfg = config.to_ffi();
self.ptr
.as_mut()
.unwrap()
.write_with_config(&__cxx_out, &cfg);
}
pub fn write_to_bytes(&mut self) -> Vec<u8> {
Vec::from(self.ptr.as_mut().unwrap().write_to_bytes().as_slice())
}
pub fn write_to_bytes_with_config(&mut self, config: Config) -> Vec<u8> {
let cfg = config.to_ffi();
Vec::from(
self.ptr
.as_mut()
.unwrap()
.write_to_bytes_with_config(&cfg)
.as_slice(),
)
}
pub fn add_command(&mut self, command: impl Command) -> Option<Commands<'_>> {
into_optional(self.ptr.as_mut().unwrap().add_command(command.get_base()))
}
pub fn add_library<'a>(&'a mut self, libname: &str) -> Dylib<'a> {
cxx::let_cxx_string!(__cxx_s = libname);
Dylib::from_ffi(self.ptr.as_mut().unwrap().add_library(&__cxx_s))
}
pub fn remove_commands_by_type(&mut self, ty: LoadCommandTypes) -> bool {
self.ptr
.as_mut()
.unwrap()
.remove_commands_by_type(ty.into())
}
pub fn functions(&self) -> generic::Functions<'_> {
generic::Functions::new(self.ptr.functions())
}
pub fn notes(&self) -> Notes<'_> {
Notes::new(self.ptr.notes())
}
pub fn fileset_name(&self) -> String {
self.ptr.fileset_name().to_string()
}
pub fn fileset_addr(&self) -> u64 {
self.ptr.fileset_addr()
}
pub fn filesets(&self) -> FilesetBinaries<'_> {
FilesetBinaries::new(self.ptr.filesets())
}
pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
to_result!(ffi::MachO_Binary::virtual_address_to_offset, &self, address);
}
pub fn segment_from_offset(&self, offset: u64) -> Option<Segment<'_>> {
into_optional(self.ptr.segment_from_offset(offset))
}
pub fn segment_from_virtual_address(&self, va: u64) -> Option<Segment<'_>> {
into_optional(self.ptr.segment_from_virtual_address(va))
}
pub fn section_from_virtual_address(&self, va: u64) -> Option<Section<'_>> {
into_optional(self.ptr.section_from_virtual_address(va))
}
pub fn get_segment(&self, name: String) -> Option<Segment<'_>> {
cxx::let_cxx_string!(__cxx_s = name);
into_optional(self.ptr.get_segment(&__cxx_s))
}
pub fn get_section(&self, segment_name: String, section_name: String) -> Option<Section<'_>> {
cxx::let_cxx_string!(seg = segment_name);
cxx::let_cxx_string!(sec = section_name);
into_optional(self.ptr.get_section(&seg, &sec))
}
pub fn fat_offset(&self) -> u64 {
self.ptr.fat_offset()
}
pub fn overlay(&self) -> &[u8] {
to_slice!(self.ptr.overlay());
}
pub fn tlv_initial_content_range(&self) -> crate::Range {
crate::Range::from_ffi(&self.ptr.tlv_initial_content_range())
}
pub fn is_valid_addr(&self, address: u64) -> bool {
self.ptr.is_valid_addr(address)
}
pub fn has_symbol(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_symbol(&__cxx_s)
}
pub fn get_symbol(&self, name: &str) -> Option<Symbol<'_>> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
into_optional(self.ptr.get_symbol(&__cxx_s))
}
pub fn has_section(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_section(&__cxx_s)
}
pub fn section_from_offset(&self, offset: u64) -> Option<Section<'_>> {
into_optional(self.ptr.section_from_offset(offset))
}
pub fn has_segment(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.has_segment(&__cxx_s)
}
pub fn has_command_type(&self, ty: LoadCommandTypes) -> bool {
self.ptr.has_command_type(ty.into())
}
pub fn get_command_type(&self, ty: LoadCommandTypes) -> Option<Commands<'_>> {
into_optional(self.ptr.get_command_type(ty.into()))
}
pub fn remove_command(&mut self, index: u32) -> bool {
self.ptr.as_mut().unwrap().remove_command(index)
}
pub fn remove_section(&mut self, name: &str, clear: bool) {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.as_mut().unwrap().remove_section(&__cxx_s, clear);
}
pub fn remove_section_from_segment(&mut self, segname: &str, secname: &str, clear: bool) {
cxx::let_cxx_string!(seg = segname);
cxx::let_cxx_string!(sec = secname);
self.ptr
.as_mut()
.unwrap()
.remove_section_seg(&seg, &sec, clear);
}
pub fn remove_signature(&mut self) -> bool {
self.ptr.as_mut().unwrap().remove_signature()
}
pub fn remove_symbol(&mut self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.as_mut().unwrap().remove_symbol(&__cxx_s)
}
pub fn can_remove(&self, sym: &Symbol<'_>) -> bool {
self.ptr.can_remove(sym.as_ffi())
}
pub fn can_remove_symbol(&self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.can_remove_symbol(&__cxx_s)
}
pub fn unexport_name(&mut self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name.to_string());
self.ptr.as_mut().unwrap().unexport_name(&__cxx_s)
}
pub fn unexport_symbol(&mut self, sym: &super::Symbol<'_>) -> bool {
self.ptr.as_mut().unwrap().unexport_symbol(sym.as_ffi())
}
pub fn add_exported_function(&mut self, address: u64, name: &str) -> Option<ExportInfo<'_>> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
into_optional(
self.ptr
.as_mut()
.unwrap()
.add_exported_function(address, &__cxx_s),
)
}
pub fn add_local_symbol(&mut self, address: u64, name: &str) -> Option<Symbol<'_>> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
into_optional(
self.ptr
.as_mut()
.unwrap()
.add_local_symbol(address, &__cxx_s),
)
}
pub fn shift(&mut self, value: u64) -> Result<(), Error> {
to_conv_result!(ffi::MachO_Binary::shift, self.ptr.pin_mut(), |_| (), value);
}
pub fn shift_linkedit(&mut self, width: u64) -> Result<(), Error> {
to_conv_result!(
ffi::MachO_Binary::shift_linkedit,
self.ptr.pin_mut(),
|_| (),
width
);
}
}
impl AsFFI<ffi::MachO_Binary> for Binary {
fn as_ffi(&self) -> &ffi::MachO_Binary {
self.ptr.as_ref().unwrap()
}
fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::MachO_Binary> {
self.ptr.pin_mut()
}
}
impl generic::Binary for Binary {
fn as_generic(&self) -> &ffi::AbstractBinary {
self.ptr.as_ref().unwrap().as_ref()
}
fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
unsafe {
Pin::new_unchecked({
(self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractBinary
as *mut ffi::AbstractBinary)
.as_mut()
.unwrap()
})
}
}
}
declare_fwd_iterator!(
BindingsInfo,
BindingInfo<'a>,
ffi::MachO_BindingInfo,
ffi::MachO_Binary,
ffi::MachO_Binary_it_bindings_info
);
declare_iterator!(
Stubs,
Stub<'a>,
ffi::MachO_Stub,
ffi::MachO_Binary,
ffi::MachO_Binary_it_stubs
);
declare_iterator!(
Notes,
Note<'a>,
ffi::MachO_NoteCommand,
ffi::MachO_Binary,
ffi::MachO_Binary_it_notes
);
declare_iterator!(
FilesetBinaries,
Binary,
ffi::MachO_Binary,
ffi::MachO_Binary,
ffi::MachO_Binary_it_fileset_binaries
);
declare_iterator!(
LazyLoadDylibInfos,
LazyLoadDylibInfo<'a>,
ffi::MachO_LazyLoadDylibInfo,
ffi::MachO_Binary,
ffi::MachO_Binary_it_lazy_load_dylib_info
);