use super::Command;
use crate::common::{FromFFI, into_optional};
use crate::declare_iterator;
use crate::to_slice;
use lief_ffi as ffi;
use std::marker::PhantomData;
use crate::macho::relocation::Relocation;
use crate::macho::section::Section;
use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Flags: u64 {
const HIGHVM = 0x1;
const FVMLIB = 0x2;
const NORELOC = 0x4;
const PROTECTED_VERSION_1 = 0x8;
const READ_ONLY = 0x10;
}
}
impl From<u64> for Flags {
fn from(value: u64) -> Self {
Flags::from_bits_truncate(value)
}
}
impl From<Flags> for u64 {
fn from(value: Flags) -> Self {
value.bits()
}
}
impl std::fmt::Display for Flags {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VmProtections: u32 {
const READ = 0x1;
const WRITE = 0x2;
const EXECUTE = 0x4;
}
}
impl From<u32> for VmProtections {
fn from(value: u32) -> Self {
VmProtections::from_bits_truncate(value)
}
}
impl From<VmProtections> for u32 {
fn from(value: VmProtections) -> Self {
value.bits()
}
}
impl std::fmt::Display for VmProtections {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
pub struct Segment<'a> {
ptr: cxx::UniquePtr<ffi::MachO_SegmentCommand>,
_owner: PhantomData<&'a ffi::MachO_Binary>,
}
impl Segment<'_> {
pub fn name(&self) -> String {
self.ptr.name().to_string()
}
pub fn virtual_address(&self) -> u64 {
self.ptr.virtual_address()
}
pub fn virtual_size(&self) -> u64 {
self.ptr.virtual_size()
}
pub fn file_size(&self) -> u64 {
self.ptr.file_size()
}
pub fn file_offset(&self) -> u64 {
self.ptr.file_offset()
}
pub fn max_protection(&self) -> u32 {
self.ptr.max_protection()
}
pub fn init_protection(&self) -> u32 {
self.ptr.init_protection()
}
pub fn numberof_sections(&self) -> u32 {
self.ptr.numberof_sections()
}
pub fn flags(&self) -> u32 {
self.ptr.flags()
}
pub fn content(&self) -> &[u8] {
to_slice!(self.ptr.content());
}
pub fn sections(&self) -> Sections<'_> {
Sections::new(self.ptr.sections())
}
pub fn relocations(&self) -> Relocations<'_> {
Relocations::new(self.ptr.relocations())
}
pub fn index(&self) -> Option<u8> {
let idx = self.ptr.index();
if idx < 0 { None } else { Some(idx as u8) }
}
pub fn get_section(&self, name: &str) -> Option<Section<'_>> {
cxx::let_cxx_string!(__cxx_s = name.to_string());
into_optional(self.ptr.get_section(&__cxx_s))
}
}
impl std::fmt::Debug for Segment<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let base = self as &dyn Command;
f.debug_struct("Segment")
.field("base", &base)
.field("name", &self.name())
.field("virtual_address", &self.virtual_address())
.field("virtual_size", &self.virtual_size())
.field("file_size", &self.file_size())
.field("file_offset", &self.file_offset())
.field("max_protection", &self.max_protection())
.field("init_protection", &self.init_protection())
.field("numberof_sections", &self.numberof_sections())
.field("flags", &self.flags())
.finish()
}
}
impl FromFFI<ffi::MachO_SegmentCommand> for Segment<'_> {
fn from_ffi(cmd: cxx::UniquePtr<ffi::MachO_SegmentCommand>) -> Self {
Self {
ptr: cmd,
_owner: PhantomData,
}
}
}
impl Command for Segment<'_> {
fn get_base(&self) -> &ffi::MachO_Command {
self.ptr.as_ref().unwrap().as_ref()
}
}
declare_iterator!(
Segments,
Segment<'a>,
ffi::MachO_SegmentCommand,
ffi::MachO_Binary,
ffi::MachO_Binary_it_segments
);
declare_iterator!(
Sections,
Section<'a>,
ffi::MachO_Section,
ffi::MachO_SegmentCommand,
ffi::MachO_SegmentCommand_it_sections
);
declare_iterator!(
Relocations,
Relocation<'a>,
ffi::MachO_Relocation,
ffi::MachO_SegmentCommand,
ffi::MachO_SegmentCommand_it_relocations
);