dynlink/
error.rs

1//! Definitions for errors for the dynamic linker.
2use std::alloc::Layout;
3
4use elf::file::Class;
5use itertools::{Either, Itertools};
6use miette::Diagnostic;
7use thiserror::Error;
8
9use crate::{
10    compartment::CompartmentId,
11    engines::LoadDirective,
12    library::{LibraryId, UnloadedLibrary},
13};
14
15#[derive(Debug, Error, Diagnostic)]
16#[error("{kind}")]
17pub struct DynlinkError {
18    pub kind: DynlinkErrorKind,
19    #[related]
20    pub related: Vec<DynlinkError>,
21}
22
23impl DynlinkError {
24    pub fn new_collect(kind: DynlinkErrorKind, related: Vec<DynlinkError>) -> Self {
25        Self { kind, related }
26    }
27
28    pub fn new(kind: DynlinkErrorKind) -> Self {
29        Self {
30            kind,
31            related: vec![],
32        }
33    }
34
35    pub fn collect<I, T>(parent_kind: DynlinkErrorKind, it: I) -> Result<Vec<T>, DynlinkError>
36    where
37        I: IntoIterator<Item = Result<T, DynlinkError>>,
38    {
39        // Collect errors and values, and then if there any errors, build a new error from them.
40        let (vals, errs): (Vec<T>, Vec<DynlinkError>) =
41            it.into_iter().partition_map(|item| match item {
42                Ok(o) => Either::Left(o),
43                Err(e) => Either::Right(e),
44            });
45
46        if errs.is_empty() {
47            Ok(vals)
48        } else {
49            Err(DynlinkError {
50                kind: parent_kind,
51                related: errs,
52            })
53        }
54    }
55}
56
57impl From<DynlinkErrorKind> for DynlinkError {
58    fn from(value: DynlinkErrorKind) -> Self {
59        Self {
60            kind: value,
61            related: vec![],
62        }
63    }
64}
65
66#[derive(Debug, Error, Diagnostic)]
67pub enum DynlinkErrorKind {
68    #[error("failed to load compartment {compartment}")]
69    CompartmentLoadFail { compartment: String },
70    #[error("failed to load library {library}")]
71    LibraryLoadFail { library: UnloadedLibrary },
72    #[error("name not found: {name}")]
73    NameNotFound { name: String },
74    #[error("failed to find symbol '{symname}' for '{sourcelib}'")]
75    SymbolLookupFail { symname: String, sourcelib: String },
76    #[error("name already exists: {name}")]
77    NameAlreadyExists { name: String },
78    #[error("parse failed: {err}")]
79    ParseError {
80        #[from]
81        err: elf::ParseError,
82    },
83    #[error("dynamic object is missing a required segment or section '{name}'")]
84    MissingSection { name: String },
85    #[error("failed to allocate {:?} within compartment {}", layout, comp)]
86    FailedToAllocate { comp: String, layout: Layout },
87    #[error("invalid allocation layout: {err}")]
88    LayoutError {
89        #[from]
90        err: std::alloc::LayoutError,
91    },
92    #[error("failed to enumerate dependencies for {library}")]
93    DepEnumerationFail { library: String },
94    #[error("library {library} had no TLS data for request")]
95    NoTLSInfo { library: String },
96    #[error("library {library} requested relocation that is unsupported")]
97    UnsupportedReloc { library: String, reloc: String },
98    #[error("failed to process relocation section '{secname}' for library '{library}'")]
99    RelocationSectionFail { secname: String, library: String },
100    #[error("library '{library}' failed to relocate")]
101    RelocationFail { library: String },
102    #[error("failed to create new backing data")]
103    NewBackingFail,
104    #[error("failed to satisfy load directive")]
105    LoadDirectiveFail { dir: LoadDirective },
106    #[error("tried to operate on an unloaded library '{library}'")]
107    UnloadedLibrary { library: String },
108    #[error("dependencies of '{library}' failed to relocate")]
109    DepsRelocFail { library: String },
110    #[error("invalid library ID '{id}'")]
111    InvalidLibraryId { id: LibraryId },
112    #[error("invalid compartment ID '{id}'")]
113    InvalidCompartmentId { id: CompartmentId },
114    #[error("invalid ELF header: {hdr_err}")]
115    InvalidELFHeader {
116        #[source]
117        #[from]
118        #[diagnostic_source]
119        hdr_err: HeaderError,
120    },
121    #[error("no entry address present")]
122    NoEntryAddress { name: String },
123}
124
125#[derive(Debug, Error, Diagnostic)]
126pub enum HeaderError {
127    #[error("class mismatch: expected {expect:?}, got {got:?}")]
128    ClassMismatch { expect: Class, got: Class },
129    #[error("ELF version mismatch: expected {expect}, got {got}")]
130    VersionMismatch { expect: u32, got: u32 },
131    #[error("OS/ABI mismatch: expected {expect}, got {got}")]
132    OSABIMismatch { expect: u8, got: u8 },
133    #[error("ABI version mismatch: expected {expect}, got {got}")]
134    ABIVersionMismatch { expect: u8, got: u8 },
135    #[error("ELF type mismatch: expected {expect}, got {got}")]
136    ELFTypeMismatch { expect: u16, got: u16 },
137    #[error("machine mismatch: expected {expect}, got {got}")]
138    MachineMismatch { expect: u16, got: u16 },
139}
140
141impl From<elf::ParseError> for DynlinkError {
142    fn from(value: elf::ParseError) -> Self {
143        Self {
144            kind: DynlinkErrorKind::ParseError { err: value },
145            related: vec![],
146        }
147    }
148}