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