use goblin::mach;
use uuid::Uuid;
use symbolic_common::types::DebugId;
type MachSegment<'mach, 'data> = &'mach mach::segment::Segment<'data>;
pub struct MachSection<'data> {
pub header: mach::segment::Section,
pub data: &'data [u8],
}
pub fn find_mach_segment<'mach, 'data>(
mach: &'mach mach::MachO<'data>,
name: &str,
) -> Option<MachSegment<'mach, 'data>> {
for segment in &mach.segments {
if segment.name().map(|seg| seg == name).unwrap_or(false) {
return Some(segment);
}
}
None
}
pub fn has_mach_segment(mach: &mach::MachO, name: &str) -> bool {
find_mach_segment(mach, name).is_some()
}
pub fn find_mach_section<'data>(
mach: &mach::MachO<'data>,
name: &str,
) -> Option<MachSection<'data>> {
let segment_name = match name {
"__eh_frame" => "__TEXT",
_ => "__DWARF",
};
let segment = match find_mach_segment(mach, segment_name) {
Some(segment) => segment,
None => return None,
};
for section in segment {
if let Ok((header, data)) = section {
if header.name().map(|sec| sec == name).unwrap_or(false) {
return match header.offset {
0 => None,
_ => Some(MachSection { header, data }),
};
}
}
}
None
}
pub fn get_mach_id(macho: &mach::MachO) -> Option<DebugId> {
for cmd in &macho.load_commands {
if let mach::load_command::CommandVariant::Uuid(ref uuid_cmd) = cmd.command {
return Uuid::from_slice(&uuid_cmd.uuid)
.ok()
.map(DebugId::from_uuid);
}
}
None
}
pub fn get_mach_vmaddr(macho: &mach::MachO) -> u64 {
for seg in &macho.segments {
if seg.name().map(|name| name == "__TEXT").unwrap_or(false) {
return seg.vmaddr;
}
}
0
}