use goblin::mach::exports::{
EXPORT_SYMBOL_FLAGS_KIND_MASK, EXPORT_SYMBOL_FLAGS_REEXPORT,
EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
Export as GoblinExport, ExportInfo as GoblinExportInfo,
};
#[derive(Debug)]
pub struct Export<'p> {
pub name: String,
pub kind: ExportKind,
pub flags: u64,
pub is_weak_definition: bool,
pub info: ExportInfo<'p>,
pub offset: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportKind {
Regular,
Absolute,
ThreadLocal,
Other(u64),
}
impl ExportKind {
fn from_flags(flags: u64) -> Self {
match flags & EXPORT_SYMBOL_FLAGS_KIND_MASK {
0x00 => Self::Regular,
0x01 => Self::ThreadLocal,
0x02 => Self::Absolute,
other => Self::Other(other),
}
}
}
#[derive(Debug)]
pub enum ExportInfo<'p> {
Regular {
address: u64,
},
Reexport {
lib: &'p str,
lib_symbol_name: Option<&'p str>,
},
Stub {
stub_offset: u64,
resolver_offset: u64,
},
}
pub struct ExportIter<'p> {
items: std::vec::IntoIter<GoblinExport<'p>>,
}
impl<'p> ExportIter<'p> {
pub(crate) fn new(items: Vec<GoblinExport<'p>>) -> Self {
Self {
items: items.into_iter(),
}
}
}
impl<'p> Iterator for ExportIter<'p> {
type Item = Export<'p>;
fn next(&mut self) -> Option<Self::Item> {
let g = self.items.next()?;
let (kind, flags, info) = decode_export_info(&g.info);
let is_weak_definition = flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0;
Some(Export {
name: g.name,
kind,
flags,
is_weak_definition,
info,
offset: g.offset,
})
}
}
fn decode_export_info<'p>(g: &GoblinExportInfo<'p>) -> (ExportKind, u64, ExportInfo<'p>) {
match *g {
GoblinExportInfo::Regular { address, flags } => (
ExportKind::from_flags(flags),
flags,
ExportInfo::Regular { address },
),
GoblinExportInfo::Reexport {
lib,
lib_symbol_name,
flags,
} => (
ExportKind::from_flags(flags),
flags,
ExportInfo::Reexport {
lib,
lib_symbol_name,
},
),
GoblinExportInfo::Stub {
stub_offset,
resolver_offset,
flags,
} => (
ExportKind::from_flags(flags),
flags,
ExportInfo::Stub {
stub_offset: u64::from(stub_offset),
resolver_offset: u64::from(resolver_offset),
},
),
}
}
pub mod flags {
pub use goblin::mach::exports::{
EXPORT_SYMBOL_FLAGS_KIND_MASK, EXPORT_SYMBOL_FLAGS_REEXPORT,
EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
};
}
#[allow(dead_code)]
const _USED: (u64, u64) = (
EXPORT_SYMBOL_FLAGS_REEXPORT,
EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER,
);