1use 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 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}