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