use core::marker::PhantomData;
use goblin::mach::symbols::{
N_ABS, N_EXT, N_INDR, N_PBUD, N_PEXT, N_SECT, N_STAB, N_TYPE, N_UNDF, N_WEAK_DEF, N_WEAK_REF,
Nlist, SymbolIterator as GoblinSymbolIter,
};
pub struct Symbol<'a, 'p> {
name: &'a str,
nlist: Nlist,
_parent: PhantomData<&'p ()>,
}
impl<'a, 'p> Symbol<'a, 'p> {
pub fn name(&self) -> &'a str {
self.name
}
pub fn n_strx(&self) -> u32 {
self.nlist.n_strx as u32
}
pub fn n_type(&self) -> u8 {
self.nlist.n_type
}
pub fn kind(&self) -> SymbolKind {
if self.is_stab() {
return SymbolKind::Stab(self.nlist.n_type);
}
match self.nlist.n_type & N_TYPE {
N_UNDF => SymbolKind::Undefined,
N_ABS => SymbolKind::Absolute,
N_SECT => SymbolKind::Section,
N_PBUD => SymbolKind::PreboundUndefined,
N_INDR => SymbolKind::Indirect,
other => SymbolKind::Other(other),
}
}
pub fn n_sect(&self) -> u8 {
(self.nlist.n_sect & 0xff) as u8
}
pub fn n_desc(&self) -> u16 {
self.nlist.n_desc
}
pub fn n_value(&self) -> u64 {
self.nlist.n_value
}
pub fn is_external(&self) -> bool {
self.nlist.n_type & N_EXT != 0
}
pub fn is_private_external(&self) -> bool {
self.nlist.n_type & N_PEXT != 0
}
pub fn is_undefined(&self) -> bool {
self.nlist.n_type & N_TYPE == N_UNDF && self.nlist.n_sect == 0
}
pub fn is_weak(&self) -> bool {
self.nlist.n_desc & (N_WEAK_REF | N_WEAK_DEF) != 0
}
pub fn is_stab(&self) -> bool {
self.nlist.n_type & N_STAB != 0
}
}
impl core::fmt::Debug for Symbol<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Symbol")
.field("name", &self.name)
.field("kind", &self.kind())
.field("external", &self.is_external())
.field("n_sect", &self.n_sect())
.field("n_value", &format_args!("0x{:x}", self.n_value()))
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
Undefined,
Absolute,
Section,
PreboundUndefined,
Indirect,
Stab(u8),
Other(u8),
}
pub struct SymbolIter<'a, 'p> {
inner: Option<GoblinSymbolIter<'a>>,
_parent: PhantomData<&'p ()>,
}
impl<'a, 'p> SymbolIter<'a, 'p> {
pub(crate) fn new(inner: Option<GoblinSymbolIter<'a>>) -> Self {
Self {
inner,
_parent: PhantomData,
}
}
}
impl<'a, 'p> Iterator for SymbolIter<'a, 'p> {
type Item = Symbol<'a, 'p>;
fn next(&mut self) -> Option<Self::Item> {
let inner = self.inner.as_mut()?;
loop {
match inner.next()? {
Ok((name, nlist)) => {
return Some(Symbol {
name,
nlist,
_parent: PhantomData,
});
}
Err(_) => continue,
}
}
}
}