use core::fmt;
use crate::model::{SectionId, SymbolId};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum SectionProblem {
NameContainsNul,
BadAlignment,
FlagsDoNotMatchKind,
MergeWithoutEntrySize,
ContentsDoNotMatchKind,
MisalignedAddress,
AddressOverflow,
}
impl fmt::Display for SectionProblem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
SectionProblem::NameContainsNul => "name contains a NUL byte",
SectionProblem::BadAlignment => "alignment is not a power of two",
SectionProblem::FlagsDoNotMatchKind => "flags are not allowed for the section's kind",
SectionProblem::MergeWithoutEntrySize => "mergeable section has an entry size of zero",
SectionProblem::ContentsDoNotMatchKind => {
"contents do not match the kind (bytes in a BSS section, or a BSS size on another kind)"
}
SectionProblem::MisalignedAddress => "address is not a multiple of the alignment",
SectionProblem::AddressOverflow => "address plus size overflows the address space",
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum SymbolProblem {
NameContainsNul,
UnknownSection,
OutOfSection,
LocalUndefined,
BadFileSymbol,
BadCommonSymbol,
CommonInExecutable,
UndefinedInExecutable,
TlsOutsideTlsSection,
}
impl fmt::Display for SymbolProblem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
SymbolProblem::NameContainsNul => "name contains a NUL byte",
SymbolProblem::UnknownSection => "defined in a section the object does not have",
SymbolProblem::OutOfSection => "lies outside its section",
SymbolProblem::LocalUndefined => "a local symbol must be defined",
SymbolProblem::BadFileSymbol => {
"a file symbol must be local and absolute, with value and size zero"
}
SymbolProblem::BadCommonSymbol => {
"a common symbol must be global, with a power-of-two alignment as its value"
}
SymbolProblem::CommonInExecutable => "an executable cannot hold a common symbol",
SymbolProblem::UndefinedInExecutable => {
"an executable cannot hold a non-weak undefined symbol"
}
SymbolProblem::TlsOutsideTlsSection => {
"a thread-local symbol is defined outside a thread-local section"
}
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum RelocationProblem {
WrongArchitecture,
OutOfSection,
Misaligned,
UnknownTarget,
InUninitializedSection,
InExecutable,
}
impl fmt::Display for RelocationProblem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
RelocationProblem::WrongArchitecture => "kind belongs to another architecture",
RelocationProblem::OutOfSection => "patches bytes outside its section",
RelocationProblem::Misaligned => "instruction relocation is not 4-byte aligned",
RelocationProblem::UnknownTarget => "target symbol or section does not exist",
RelocationProblem::InUninitializedSection => {
"patches a BSS section, which has no bytes"
}
RelocationProblem::InExecutable => "executables carry no relocations",
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum ModelError {
Section {
section: SectionId,
problem: SectionProblem,
},
Symbol {
symbol: SymbolId,
problem: SymbolProblem,
},
Relocation {
section: SectionId,
index: usize,
problem: RelocationProblem,
},
SectionsOverlap {
first: SectionId,
second: SectionId,
},
EntryNotExecutable {
entry: u64,
},
UnknownSection {
section: SectionId,
},
InvalidAlignment {
align: u64,
},
AppendToBss,
SizeOverflow,
TooManyItems,
}
impl fmt::Display for ModelError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ModelError::Section { section, problem } => {
write!(f, "section #{}: {problem}", section.index())
}
ModelError::Symbol { symbol, problem } => {
write!(f, "symbol #{}: {problem}", symbol.index())
}
ModelError::Relocation {
section,
index,
problem,
} => write!(
f,
"relocation #{index} of section #{}: {problem}",
section.index()
),
ModelError::SectionsOverlap { first, second } => write!(
f,
"sections #{} and #{} overlap in memory",
first.index(),
second.index()
),
ModelError::EntryNotExecutable { entry } => {
write!(
f,
"entry point {entry:#x} is not inside an executable section"
)
}
ModelError::UnknownSection { section } => {
write!(f, "the object has no section #{}", section.index())
}
ModelError::InvalidAlignment { align } => {
write!(f, "alignment {align} is not a power of two")
}
ModelError::AppendToBss => {
f.write_str("cannot append bytes to a BSS section; reserve space instead")
}
ModelError::SizeOverflow => f.write_str("section size overflows"),
ModelError::TooManyItems => f.write_str("too many sections or symbols to number"),
}
}
}
impl core::error::Error for ModelError {}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum WriteError {
Invalid(ModelError),
ReservedSectionName {
section: SectionId,
},
SegmentsSharePage {
first: SectionId,
second: SectionId,
},
NoRoomForHeaders,
Unsupported {
what: &'static str,
},
TooLarge,
}
impl fmt::Display for WriteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
WriteError::Invalid(err) => write!(f, "invalid object: {err}"),
WriteError::ReservedSectionName { section } => write!(
f,
"section #{} uses a name the writer reserves for itself",
section.index()
),
WriteError::SegmentsSharePage { first, second } => write!(
f,
"sections #{} and #{} need different page permissions but share a page",
first.index(),
second.index()
),
WriteError::NoRoomForHeaders => f.write_str(
"the lowest section is too close to address zero to map the headers below it",
),
WriteError::Unsupported { what } => write!(f, "unsupported: {what}"),
WriteError::TooLarge => f.write_str("the file would exceed the format's size limits"),
}
}
}
impl core::error::Error for WriteError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
WriteError::Invalid(err) => Some(err),
_ => None,
}
}
}
impl From<ModelError> for WriteError {
fn from(err: ModelError) -> Self {
WriteError::Invalid(err)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum ReadError {
BadMagic,
Truncated {
what: &'static str,
},
Malformed {
what: &'static str,
},
Unsupported {
what: &'static str,
value: u64,
},
LimitExceeded {
limit: &'static str,
},
Invalid(ModelError),
}
impl fmt::Display for ReadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ReadError::BadMagic => {
f.write_str("not an object file of this format (bad magic number)")
}
ReadError::Truncated { what } => {
write!(f, "truncated: {what} runs past the end of the input")
}
ReadError::Malformed { what } => write!(f, "malformed: {what}"),
ReadError::Unsupported { what, value } => write!(f, "unsupported {what} ({value:#x})"),
ReadError::LimitExceeded { limit } => write!(f, "limit exceeded: {limit}"),
ReadError::Invalid(err) => write!(f, "invalid object: {err}"),
}
}
}
impl core::error::Error for ReadError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
ReadError::Invalid(err) => Some(err),
_ => None,
}
}
}
impl From<ModelError> for ReadError {
fn from(err: ModelError) -> Self {
ReadError::Invalid(err)
}
}