use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::{fmt, result};
use crate::common::*;
use crate::Bytes;
mod util;
pub use util::StringTable;
mod any;
pub use any::*;
#[cfg(feature = "archive")]
pub mod archive;
#[cfg(feature = "coff")]
pub mod coff;
#[cfg(feature = "elf")]
pub mod elf;
#[cfg(feature = "macho")]
pub mod macho;
#[cfg(feature = "pe")]
pub mod pe;
mod traits;
pub use traits::*;
#[cfg(feature = "wasm")]
pub mod wasm;
mod private {
pub trait Sealed {}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Error(&'static str);
impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
pub type Result<T> = result::Result<T, Error>;
trait ReadError<T> {
fn read_error(self, error: &'static str) -> Result<T>;
}
impl<T> ReadError<T> for result::Result<T, ()> {
fn read_error(self, error: &'static str) -> Result<T> {
self.map_err(|()| Error(error))
}
}
impl<T> ReadError<T> for Option<T> {
fn read_error(self, error: &'static str) -> Result<T> {
self.ok_or(Error(error))
}
}
#[cfg(all(
unix,
not(target_os = "macos"),
target_pointer_width = "32",
feature = "elf"
))]
pub type NativeFile<'data> = elf::ElfFile32<'data>;
#[cfg(all(
unix,
not(target_os = "macos"),
target_pointer_width = "64",
feature = "elf"
))]
pub type NativeFile<'data> = elf::ElfFile64<'data>;
#[cfg(all(target_os = "macos", target_pointer_width = "32", feature = "macho"))]
pub type NativeFile<'data> = macho::MachOFile32<'data>;
#[cfg(all(target_os = "macos", target_pointer_width = "64", feature = "macho"))]
pub type NativeFile<'data> = macho::MachOFile64<'data>;
#[cfg(all(target_os = "windows", target_pointer_width = "32", feature = "pe"))]
pub type NativeFile<'data> = pe::PeFile32<'data>;
#[cfg(all(target_os = "windows", target_pointer_width = "64", feature = "pe"))]
pub type NativeFile<'data> = pe::PeFile64<'data>;
#[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))]
pub type NativeFile<'data> = wasm::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,
None,
Undefined,
Absolute,
Common,
Section(SectionIndex),
}
impl SymbolSection {
#[inline]
pub fn index(self) -> Option<SectionIndex> {
if let SymbolSection::Section(index) = self {
Some(index)
} else {
None
}
}
}
pub trait SymbolMapEntry {
fn address(&self) -> u64;
}
#[derive(Debug, Default, Clone)]
pub struct SymbolMap<T: SymbolMapEntry> {
symbols: Vec<T>,
}
impl<T: SymbolMapEntry> SymbolMap<T> {
pub fn new(mut symbols: Vec<T>) -> Self {
symbols.sort_unstable_by_key(|s| s.address());
SymbolMap { symbols }
}
pub fn get(&self, address: u64) -> Option<&T> {
let index = match self
.symbols
.binary_search_by_key(&address, |symbol| symbol.address())
{
Ok(index) => index,
Err(index) => index.checked_sub(1)?,
};
self.symbols.get(index)
}
#[inline]
pub fn symbols(&self) -> &[T] {
&self.symbols
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SymbolMapName<'data> {
address: u64,
name: &'data str,
}
impl<'data> SymbolMapName<'data> {
pub fn new(address: u64, name: &'data str) -> Self {
SymbolMapName { address, name }
}
#[inline]
pub fn address(&self) -> u64 {
self.address
}
#[inline]
pub fn name(&self) -> &'data str {
self.name
}
}
impl<'data> SymbolMapEntry for SymbolMapName<'data> {
#[inline]
fn address(&self) -> u64 {
self.address
}
}
#[derive(Debug, Default, Clone)]
pub struct ObjectMap<'data> {
symbols: SymbolMap<ObjectMapEntry<'data>>,
objects: Vec<&'data [u8]>,
}
impl<'data> ObjectMap<'data> {
pub fn get(&self, address: u64) -> Option<&ObjectMapEntry<'data>> {
self.symbols
.get(address)
.filter(|entry| entry.size == 0 || address.wrapping_sub(entry.address) < entry.size)
}
#[inline]
pub fn symbols(&self) -> &[ObjectMapEntry<'data>] {
self.symbols.symbols()
}
#[inline]
pub fn objects(&self) -> &[&'data [u8]] {
&self.objects
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ObjectMapEntry<'data> {
address: u64,
size: u64,
name: &'data [u8],
object: usize,
}
impl<'data> ObjectMapEntry<'data> {
#[inline]
pub fn address(&self) -> u64 {
self.address
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn name(&self) -> &'data [u8] {
self.name
}
#[inline]
pub fn object_index(&self) -> usize {
self.object
}
#[inline]
pub fn object(&self, map: &ObjectMap<'data>) -> &'data [u8] {
map.objects[self.object]
}
}
impl<'data> SymbolMapEntry for ObjectMapEntry<'data> {
#[inline]
fn address(&self) -> u64 {
self.address
}
}
#[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
}
#[inline]
pub fn addend(&self) -> i64 {
self.addend
}
#[inline]
pub fn set_addend(&mut self, addend: i64) {
self.addend = addend
}
#[inline]
pub fn has_implicit_addend(&self) -> bool {
self.implicit_addend
}
}
fn data_range(data: Bytes, data_address: u64, range_address: u64, size: u64) -> Option<&[u8]> {
let offset = range_address.checked_sub(data_address)?;
let data = data.read_bytes_at(offset as usize, size as usize).ok()?;
Some(data.0)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CompressedData<'data> {
pub format: CompressionFormat,
pub data: &'data [u8],
pub uncompressed_size: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CompressionFormat {
None,
Unknown,
Zlib,
}
impl<'data> CompressedData<'data> {
#[inline]
pub fn none(data: &'data [u8]) -> Self {
CompressedData {
format: CompressionFormat::None,
data,
uncompressed_size: data.len(),
}
}
pub fn decompress(self) -> Result<Cow<'data, [u8]>> {
match self.format {
CompressionFormat::None => Ok(Cow::Borrowed(self.data)),
#[cfg(feature = "compression")]
CompressionFormat::Zlib => {
let mut decompressed = Vec::with_capacity(self.uncompressed_size);
let mut decompress = flate2::Decompress::new(true);
decompress
.decompress_vec(
self.data,
&mut decompressed,
flate2::FlushDecompress::Finish,
)
.ok()
.read_error("Invalid zlib compressed data")?;
Ok(Cow::Owned(decompressed))
}
_ => Err(Error("Unsupported compressed data.")),
}
}
}