elb 0.4.0

A library that supports reading ELF files and patching RPATH, RUNPATH and interpreter.
Documentation
use thiserror::Error;

use crate::SectionKind;
use crate::SegmentKind;

/// ELF-specific error.
#[derive(Error)]
#[allow(missing_docs)]
pub enum Error {
    #[error("Not an ELF file")]
    NotElf,
    #[error("Invalid ELF class: {0}")]
    InvalidClass(u8),
    #[error("Invalid byte order: {0}")]
    InvalidByteOrder(u8),
    #[error("Invalid version: {0}")]
    InvalidVersion(u8),
    #[error("Invalid file version: {0}")]
    InvalidFileVersion(u32),
    #[error("Invalid ELF header size: {0}")]
    InvalidHeaderLen(u16),
    #[error("Invalid section header string table index: {0}")]
    InvalidSectionHeaderStringTableIndex(u16),
    #[error("Invalid entry point: {0:#x}")]
    InvalidEntryPoint(u64),
    #[error("Invalid PHDR segment: {0}")]
    InvalidProgramHeaderSegment(&'static str),
    #[error("Invalid file kind: {0}")]
    InvalidFileKind(u16),
    #[error("Invalid segment kind: {0}")]
    InvalidSegmentKind(u32),
    #[error("Invalid segment size: {0}")]
    InvalidSegmentLen(u16),
    #[error("Invalid section kind: {0}")]
    InvalidSectionKind(u32),
    #[error("Invalid section size: {0}")]
    InvalidSectionLen(u16),
    #[error("Invalid first section kind: {0:?} (should be NULL)")]
    InvalidFirstSectionKind(SectionKind),
    #[error("Too many sections: {0}")]
    TooManySections(usize),
    #[error("Invalid ALLOC section: should be covered by LOAD segment: {0:#x}..{1:#x}")]
    SectionNotCovered(u64, u64),
    #[error("Invalid dynamic entry kind: {0:#x}")]
    InvalidDynamicEntryKind(u32),
    #[error("Invalid alignment kind: {0}")]
    InvalidAlign(u64),
    #[error(
        "Misaligned segment: file offsets range = {0:#x}..{1:#x}, \
        memory addresses range = {2:#x}..{3:#x}, alignment = {4}"
    )]
    MisalignedSegment(u64, u64, u64, u64, u64),
    #[error("Misaligned section: memory addresses range = {0:#x}..{1:#x}, alignment = {2}")]
    MisalignedSection(u64, u64, u64),
    #[error("Segments overlap: {0:#x}..{1:#x}, {2:#x}..{3:#x}")]
    SegmentsOverlap(u64, u64, u64, u64),
    #[error("LOAD segments are not sorted by virtual address")]
    SegmentsNotSorted,
    #[error("Segment {0:?} should preceed any LOAD segment")]
    NotPreceedingLoadSegment(SegmentKind),
    #[error("Only one {0:?} segment is allowed")]
    MultipleSegments(SegmentKind),
    #[error("Only one {0:?} section is allowed")]
    MultipleSections(SectionKind),
    #[error("Overflow: {0}")]
    TooBig(&'static str),
    #[error("Word overflow: {0}")]
    TooBigWord(u64),
    #[error("Signed word overflow: {0}")]
    TooBigSignedWord(i64),
    #[error("Overlap: {0}")]
    Overlap(&'static str),
    #[error("Failed to allocate new section")]
    SectionAlloc,
    #[error("Failed to allocate new segment")]
    SegmentAlloc,
    #[error("Failed to allocate in-file space")]
    FileSpaceAlloc,
    #[error("Input/output error: {0}")]
    #[cfg(feature = "std")]
    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
    Io(std::io::Error),
    #[error("Invalid C-string")]
    CStr,
    #[error("Unexpected EOF")]
    UnexpectedEof,
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl From<std::io::Error> for Error {
    fn from(other: std::io::Error) -> Self {
        if other.kind() == std::io::ErrorKind::UnexpectedEof {
            Self::UnexpectedEof
        } else {
            Self::Io(other)
        }
    }
}

#[cfg(feature = "std")]
impl From<std::io::ErrorKind> for Error {
    fn from(other: std::io::ErrorKind) -> Self {
        if other == std::io::ErrorKind::UnexpectedEof {
            Self::UnexpectedEof
        } else {
            Self::Io(other.into())
        }
    }
}

impl From<alloc::ffi::FromVecWithNulError> for Error {
    fn from(_other: alloc::ffi::FromVecWithNulError) -> Self {
        Self::CStr
    }
}

impl core::fmt::Debug for Error {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        core::fmt::Display::fmt(self, f)
    }
}

pub(crate) fn check_u32(word: u64, name: &'static str) -> Result<(), Error> {
    if word > u32::MAX as u64 {
        return Err(Error::TooBig(name));
    }
    Ok(())
}