//! "Nlist" style symbols in this binary - beware, like most symbol tables in most binary formats, they are strippable, and should not be relied upon, see the imports and exports modules for something more permanent. //! //! Symbols are essentially a type, offset, and the symbol name
usecrate::container::{self, Container}; usecrate::error; usecrate::mach::load_command; use core::fmt::{self, Debug}; use scroll::ctx; use scroll::ctx::SizeWith; use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
// The n_type field really contains four fields which are used via the following masks. /// if any of these bits set, a symbolic debugging entry pubconst N_STAB: u8 = 0xe0; /// private external symbol bit pubconst N_PEXT: u8 = 0x10; /// mask for the type bits pubconst N_TYPE: u8 = 0x0e; /// external symbol bit, set for external symbols pubconst N_EXT: u8 = 0x01;
// If the type is N_SECT then the n_sect field contains an ordinal of the // section the symbol is defined in. The sections are numbered from 1 and // refer to sections in order they appear in the load commands for the file // they are in. This means the same ordinal may very well refer to different // sections in different files.
// The n_value field for all symbol table entries (including N_STAB's) gets // updated by the link editor based on the value of it's n_sect field and where // the section n_sect references gets relocated. If the value of the n_sect // field is NO_SECT then it's n_value field is not changed by the link editor. /// symbol is not in any section pubconst NO_SECT: u8 = 0; /// 1 thru 255 inclusive pubconst MAX_SECT: u8 = 255;
/// undefined, n_sect == NO_SECT pubconst N_UNDF: u8 = 0x0; /// absolute, n_sect == NO_SECT pubconst N_ABS: u8 = 0x2; /// defined in section number n_sect pubconst N_SECT: u8 = 0xe; /// prebound undefined (defined in a dylib) pubconst N_PBUD: u8 = 0xc; /// indirect pubconst N_INDR: u8 = 0xa;
/// Mask for reference flags of `n_desc` field. pubconst REFERENCE_TYPE: u16 = 0xf; /// This symbol is a reference to an external non-lazy (data) symbol. pubconst REFERENCE_FLAG_UNDEFINED_NON_LAZY: u16 = 0x0; /// This symbol is a reference to an external lazy symbol—that is, to a function call. pubconst REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 0x1; /// This symbol is defined in this module. pubconst REFERENCE_FLAG_DEFINED: u16 = 0x2; /// This symbol is defined in this module and is visible only to modules within this /// shared library. pubconst REFERENCE_FLAG_PRIVATE_DEFINED: u16 = 0x3; /// This symbol is defined in another module in this file, is a non-lazy (data) symbol, /// and is visible only to modules within this shared library. pubconst REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: u16 = 0x4; /// This symbol is defined in another module in this file, is a lazy (function) symbol, /// and is visible only to modules within this shared library. pubconst REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: u16 = 0x5;
// Additional flags of n_desc field.
/// Must be set for any defined symbol that is referenced by dynamic-loader APIs /// (such as dlsym and NSLookupSymbolInImage) and not ordinary undefined symbol /// references. The `strip` tool uses this bit to avoid removing symbols that must /// exist: If the symbol has this bit set, `strip` does not strip it. pubconst REFERENCED_DYNAMICALLY: u16 = 0x10; /// Sometimes used by the dynamic linker at runtime in a fully linked image. Do not /// set this bit in a fully linked image. pubconst N_DESC_DISCARDED: u16 = 0x20; /// When set in a relocatable object file (file type MH_OBJECT) on a defined symbol, /// indicates to the static linker to never dead-strip the symbol. // (Note that the same bit (0x20) is used for two nonoverlapping purposes.) pubconst N_NO_DEAD_STRIP: u16 = 0x20; /// Indicates that this undefined symbol is a weak reference. If the dynamic linker /// cannot find a definition for this symbol, it sets the address of this symbol to 0. /// The static linker sets this symbol given the appropriate weak-linking flags. pubconst N_WEAK_REF: u16 = 0x40; /// Indicates that this symbol is a weak definition. If the static linker or the /// dynamic linker finds another (non-weak) definition for this symbol, the weak /// definition is ignored. Only symbols in a coalesced section can be marked as a /// weak definition. pubconst N_WEAK_DEF: u16 = 0x80;
#[repr(C)] #[derive(Clone, Copy, Pread, Pwrite, SizeWith, IOread, IOwrite)] pubstruct Nlist32 { /// index into the string table pub n_strx: u32, /// type flag, see below pub n_type: u8, /// section number or NO_SECT pub n_sect: u8, /// see <mach-o/stab.h> pub n_desc: u16, /// value of this symbol (or stab offset) pub n_value: u32,
}
#[repr(C)] #[derive(Clone, Copy, Pread, Pwrite, SizeWith, IOread, IOwrite)] pubstruct Nlist64 { /// index into the string table pub n_strx: u32, /// type flag, see below pub n_type: u8, /// section number or NO_SECT pub n_sect: u8, /// see <mach-o/stab.h> pub n_desc: u16, /// value of this symbol (or stab offset) pub n_value: u64,
}
#[derive(Debug, Clone)] pubstruct Nlist { /// index into the string table pub n_strx: usize, /// type flag, see below pub n_type: u8, /// section number or NO_SECT pub n_sect: usize, /// see <mach-o/stab.h> pub n_desc: u16, /// value of this symbol (or stab offset) pub n_value: u64,
}
impl Nlist { /// Gets this symbol's type in bits 0xe pubfn get_type(&self) -> u8 { self.n_type & N_TYPE
} /// Gets the str representation of the type of this symbol pubfn type_str(&self) -> &'static str {
n_type_to_str(self.get_type())
} /// Whether this symbol is global or not pubfn is_global(&self) -> bool { self.n_type & N_EXT != 0
} /// Whether this symbol is weak or not pubfn is_weak(&self) -> bool { self.n_desc & (N_WEAK_REF | N_WEAK_DEF) != 0
} /// Whether this symbol is undefined or not pubfn is_undefined(&self) -> bool { self.n_sect == 0 && self.n_type & N_TYPE == N_UNDF
} /// Whether this symbol is a symbolic debugging entry pubfn is_stab(&self) -> bool { self.n_type & N_STAB != 0
}
}
/// A zero-copy "nlist" style symbol table ("stab"), including the string table pubstruct Symbols<'a> {
data: &'a [u8],
start: usize,
nsyms: usize, // TODO: we can use an actual strtab here and tie it to symbols lifetime
strtab: usize,
ctx: container::Ctx,
}
impl<'a, 'b> IntoIterator for &'b Symbols<'a> { type Item = <SymbolIterator<'a> as Iterator>::Item; type IntoIter = SymbolIterator<'a>; fn into_iter(self) -> Self::IntoIter { self.iter()
}
}
impl<'a> Symbols<'a> { /// Creates a new symbol table with `count` elements, from the `start` offset, using the string table at `strtab`, with a _default_ ctx. //// /// **Beware**, this will provide incorrect results if you construct this on a 32-bit mach binary, using a 64-bit machine; use `parse` instead if you want 32/64 bit support pubfn new(
bytes: &'a [u8],
start: usize,
count: usize,
strtab: usize,
) -> error::Result<Symbols<'a>> { let nsyms = count;
Ok(Symbols {
data: bytes,
start,
nsyms,
strtab,
ctx: container::Ctx::default(),
})
} pubfn parse(
bytes: &'a [u8],
symtab: &load_command::SymtabCommand,
ctx: container::Ctx,
) -> error::Result<Symbols<'a>> { // we need to normalize the strtab offset before we receive the truncated bytes in pread_with let strtab = symtab
.stroff
.checked_sub(symtab.symoff)
.ok_or_else(|| error::Error::Malformed("invalid symbol table offset".into()))?;
bytes.pread_with(
symtab.symoff as usize,
SymbolsCtx {
nsyms: symtab.nsyms as usize,
strtab: strtab as usize,
ctx,
},
)
}
/// Parses a single Nlist symbol from the binary, with its accompanying name pubfn get(&self, index: usize) -> crate::error::Result<(&e='color:blue'>'a str, Nlist)> { let sym: Nlist = self
.data
.pread_with(self.start + (index * Nlist::size_with(&self.ctx)), self.ctx)?; let name = self.data.pread(self.strtab + sym.n_strx)?;
Ok((name, sym))
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.