use crate::alloc::vec::Vec;
use crate::common::{
FileFlags, RelocationEncoding, RelocationKind, SectionFlags, SectionKind, SymbolFlags,
SymbolKind, SymbolScope,
};
mod any;
pub use any::*;
mod coff;
pub use coff::*;
mod elf;
pub use elf::*;
mod macho;
pub use macho::*;
mod pe;
pub use pe::*;
mod traits;
pub use traits::*;
#[cfg(feature = "wasm")]
mod wasm;
#[cfg(feature = "wasm")]
pub use wasm::*;
#[cfg(target_os = "linux")]
pub type NativeFile<'data> = ElfFile<'data>;
#[cfg(target_os = "macos")]
pub type NativeFile<'data> = MachOFile<'data>;
#[cfg(target_os = "windows")]
pub type NativeFile<'data> = PeFile<'data>;
#[cfg(all(feature = "wasm", target_arch = "wasm32"))]
pub type NativeFile<'data> = WasmFile<'data>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SectionIndex(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SymbolIndex(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SymbolSection {
Unknown,
Undefined,
Absolute,
Common,
Section(SectionIndex),
}
impl SymbolSection {
#[inline]
pub fn index(self) -> Option<SectionIndex> {
if let SymbolSection::Section(index) = self {
Some(index)
} else {
None
}
}
}
#[derive(Debug)]
pub struct Symbol<'data> {
name: Option<&'data str>,
address: u64,
size: u64,
kind: SymbolKind,
section: SymbolSection,
weak: bool,
scope: SymbolScope,
flags: SymbolFlags<SectionIndex>,
}
impl<'data> Symbol<'data> {
#[inline]
pub fn kind(&self) -> SymbolKind {
self.kind
}
#[inline]
pub fn section(&self) -> SymbolSection {
self.section
}
#[inline]
pub fn section_index(&self) -> Option<SectionIndex> {
self.section.index()
}
#[inline]
pub fn is_undefined(&self) -> bool {
self.section == SymbolSection::Undefined
}
#[inline]
fn is_common(&self) -> bool {
self.section == SymbolSection::Common
}
#[inline]
pub fn is_weak(&self) -> bool {
self.weak
}
#[inline]
pub fn is_global(&self) -> bool {
!self.is_local()
}
#[inline]
pub fn is_local(&self) -> bool {
self.scope == SymbolScope::Compilation
}
#[inline]
pub fn scope(&self) -> SymbolScope {
self.scope
}
#[inline]
pub fn flags(&self) -> SymbolFlags<SectionIndex> {
self.flags
}
#[inline]
pub fn name(&self) -> Option<&'data str> {
self.name
}
#[inline]
pub fn address(&self) -> u64 {
self.address
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
}
#[derive(Debug)]
pub struct SymbolMap<'data> {
symbols: Vec<Symbol<'data>>,
}
impl<'data> SymbolMap<'data> {
pub fn get(&self, address: u64) -> Option<&Symbol<'data>> {
self.symbols
.binary_search_by(|symbol| {
if address < symbol.address {
std::cmp::Ordering::Greater
} else if address < symbol.address + symbol.size {
std::cmp::Ordering::Equal
} else {
std::cmp::Ordering::Less
}
})
.ok()
.and_then(|index| self.symbols.get(index))
}
pub fn symbols(&self) -> &[Symbol<'data>] {
&self.symbols
}
fn filter(symbol: &Symbol<'_>) -> bool {
match symbol.kind() {
SymbolKind::Unknown | SymbolKind::Text | SymbolKind::Data => {}
SymbolKind::Null
| SymbolKind::Section
| SymbolKind::File
| SymbolKind::Label
| SymbolKind::Tls => {
return false;
}
}
!symbol.is_undefined() && !symbol.is_common() && symbol.size() > 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RelocationTarget {
Symbol(SymbolIndex),
Section(SectionIndex),
}
#[derive(Debug)]
pub struct Relocation {
kind: RelocationKind,
encoding: RelocationEncoding,
size: u8,
target: RelocationTarget,
addend: i64,
implicit_addend: bool,
}
impl Relocation {
#[inline]
pub fn kind(&self) -> RelocationKind {
self.kind
}
#[inline]
pub fn encoding(&self) -> RelocationEncoding {
self.encoding
}
#[inline]
pub fn size(&self) -> u8 {
self.size
}
#[inline]
pub fn target(&self) -> RelocationTarget {
self.target
}
pub fn addend(&self) -> i64 {
self.addend
}
pub fn set_addend(&mut self, addend: i64) {
self.addend = addend
}
pub fn has_implicit_addend(&self) -> bool {
self.implicit_addend
}
}
fn data_range(data: &[u8], data_address: u64, range_address: u64, size: u64) -> Option<&[u8]> {
if range_address >= data_address {
let start_offset = (range_address - data_address) as usize;
let end_offset = start_offset + size as usize;
if end_offset <= data.len() {
return Some(&data[start_offset..end_offset]);
}
}
None
}