1use dynlink::{
2 engines::LoadCtx,
3 library::{AllowedGates, LibraryId, UnloadedLibrary},
4 symbol::LookupFlags,
5};
6use happylock::ThreadKey;
7use monitor_api::LibraryInfoRaw;
8use secgate::util::Descriptor;
9use twizzler_abi::object::{MAX_SIZE, NULLPAGE_SIZE};
10use twizzler_rt_abi::{
11 bindings::{ctor_set, link_map},
12 debug::LinkMap,
13 error::{ArgumentError, GenericError, ResourceError, TwzError},
14 object::ObjID,
15};
16
17use super::Monitor;
18
19pub struct LibraryHandle {
21 comp: ObjID,
22 id: LibraryId,
23}
24
25impl Monitor {
26 pub fn get_library_info(
29 &self,
30 instance: ObjID,
31 thread: ObjID,
32 desc: Descriptor,
33 ) -> Result<LibraryInfoRaw, TwzError> {
34 let (_, ref mut comps, ref dynlink, ref libhandles, _) =
35 *self.locks.lock(ThreadKey::get().unwrap());
36 let handle = libhandles
37 .lookup(instance, desc)
38 .ok_or(ArgumentError::InvalidArgument)?;
39 let lib = dynlink
41 .get_library(handle.id)
42 .map_err(|_| GenericError::Internal)?;
43 let pt = comps.get_mut(instance)?.get_per_thread(thread);
45 let name_len = pt.write_bytes(lib.name.as_bytes());
46 let dynamic_ptr = lib.dynamic_ptr();
47 Ok(LibraryInfoRaw {
48 name_len,
49 compartment_id: handle.comp,
50 objid: lib.full_obj.id(),
51 slot: lib.full_obj.load_addr() / MAX_SIZE,
52 start: (lib.full_obj.load_addr() + NULLPAGE_SIZE) as *mut _,
53 len: MAX_SIZE - NULLPAGE_SIZE * 2,
54 dl_info: twizzler_rt_abi::debug::DlPhdrInfo {
55 addr: lib.base_addr(),
56 name: core::ptr::null(),
57 phdr: lib.get_phdrs_raw().ok_or(GenericError::Internal)?.0 as *const _,
58 phnum: lib.get_phdrs_raw().ok_or(GenericError::Internal)?.1 as u32,
59 adds: 0,
60 subs: 0,
61 tls_modid: lib.tls_id.map(|t| t.tls_id()).unwrap_or(0) as usize,
62 tls_data: core::ptr::null_mut(),
63 },
64 desc,
65 link_map: LinkMap(link_map {
66 next: core::ptr::null_mut(),
67 prev: core::ptr::null_mut(),
68 name: core::ptr::null_mut(),
69 ld: dynamic_ptr.unwrap_or(core::ptr::null_mut()).cast(),
70 addr: lib.base_addr(),
71 }),
72 })
73 }
74
75 pub fn get_library_handle(
77 &self,
78 caller: ObjID,
79 comp: Option<Descriptor>,
80 num: usize,
81 ) -> Result<Descriptor, TwzError> {
82 let (_, ref mut comps, ref dynlink, ref mut handles, ref comphandles) =
83 *self.locks.lock(ThreadKey::get().unwrap());
84 let comp_id = comp
85 .map(|comp| comphandles.lookup(caller, comp).map(|ch| ch.instance))
86 .unwrap_or(Some(caller))
87 .ok_or(TwzError::INVALID_ARGUMENT)?;
88 let rc = comps.get(comp_id)?;
89 let dcomp = dynlink
91 .get_compartment(rc.compartment_id)
92 .map_err(|_| GenericError::Internal)?;
93 let id = dcomp
94 .library_ids()
95 .nth(num)
96 .ok_or(TwzError::INVALID_ARGUMENT)?;
97 handles
98 .insert(caller, LibraryHandle { comp: comp_id, id })
99 .ok_or(ResourceError::OutOfResources.into())
100 }
101
102 pub fn load_library_by_name(
106 &self,
107 caller: ObjID,
108 thread: ObjID,
109 name_len: usize,
110 id: Option<ObjID>,
111 ) -> Result<(Descriptor, usize), TwzError> {
112 let (_, ref mut comps, ref mut dynlink, ref mut handles, _) =
113 *self.locks.lock(ThreadKey::get().unwrap());
114 let rc = comps.get_mut(caller)?;
115 let name_bytes = rc.get_per_thread(thread).read_bytes(name_len);
116 let name = std::str::from_utf8(&name_bytes)
117 .map_err(|_| ArgumentError::InvalidArgument)?
118 .to_string();
119 let comp_id = rc.compartment_id;
120
121 let (lib_id, loads) = if let Some(id) = dynlink.lookup_library(comp_id, &name) {
123 (id, None)
124 } else {
125 let unlib = if let Some(id) = id {
127 UnloadedLibrary::new_object(name.clone(), id)
128 } else {
129 UnloadedLibrary::new(name.clone())
130 };
131 let mut load_ctx = LoadCtx::default();
132 let loads = dynlink
133 .load_library_in_compartment(comp_id, unlib, AllowedGates::Private, &mut load_ctx)
134 .map_err(|_| TwzError::NOT_FOUND)?;
135 tracing::debug!("loaded library '{}'", name);
136 let root_id = loads.first().ok_or(GenericError::Internal)?.lib;
137 dynlink
139 .relocate_all(root_id)
140 .map_err(|_| GenericError::Internal)?;
141 (root_id, Some(loads))
142 };
143
144 let ctors = if loads.is_none() {
145 vec![]
146 } else {
147 dynlink
148 .build_ctors_list(lib_id, Some(comp_id), loads)
149 .map_err(|_| TwzError::INVALID_ARGUMENT)?
150 };
151
152 let bytes = unsafe {
153 core::slice::from_raw_parts(
154 ctors.as_ptr().cast::<u8>(),
155 ctors.len() * core::mem::size_of::<ctor_set>(),
156 )
157 };
158 let ctor_len = rc.get_per_thread(thread).write_bytes(bytes);
159
160 handles
161 .insert(
162 caller,
163 LibraryHandle {
164 comp: caller,
165 id: lib_id,
166 },
167 )
168 .ok_or(ResourceError::OutOfResources.into())
169 .map(|h| (h, ctor_len))
170 }
171
172 pub fn drop_library_handle(&self, caller: ObjID, desc: Descriptor) {
174 self.library_handles
176 .write(ThreadKey::get().unwrap())
177 .remove(caller, desc);
178 }
179
180 pub fn lookup_symbol(
184 &self,
185 caller: ObjID,
186 thread: ObjID,
187 lib_desc: Option<Descriptor>,
188 name_len: usize,
189 ) -> Result<usize, TwzError> {
190 let (_, ref mut comps, ref dynlink, ref libhandles, _) =
191 *self.locks.lock(ThreadKey::get().unwrap());
192 let rc = comps.get_mut(caller)?;
193 let name_bytes = rc.get_per_thread(thread).read_bytes(name_len);
194 let name = std::str::from_utf8(&name_bytes).map_err(|_| ArgumentError::InvalidArgument)?;
195
196 tracing::debug!(
197 "looking up symbol '{}' for caller {}, lib_desc = {:?}",
198 name,
199 caller,
200 lib_desc
201 );
202 match lib_desc {
203 Some(desc) => {
204 let lib = libhandles
205 .lookup(caller, desc)
206 .ok_or(ArgumentError::InvalidArgument)?;
207 let deps = dynlink.build_deps_search_list(lib.id);
208 let sym = dynlink
209 .lookup_symbol(
210 lib.id,
211 name,
212 LookupFlags::SKIP_SECGATE_CHECK | LookupFlags::ALLOW_WEAK,
213 &deps,
214 )
215 .map_err(|_| TwzError::NOT_FOUND)?;
216 return Ok(sym.reloc_value() as usize);
217 }
218 None => {
219 for lid in dynlink
221 .get_compartment(rc.compartment_id)
222 .map_err(|_| GenericError::Internal)?
223 .library_ids()
224 {
225 let deps = dynlink.build_deps_search_list(lid);
226 if let Ok(sym) = dynlink.lookup_symbol(
227 lid,
228 name,
229 LookupFlags::SKIP_SECGATE_CHECK | LookupFlags::ALLOW_WEAK,
230 &deps,
231 ) {
232 return Ok(sym.reloc_value() as usize);
233 }
234 }
235 }
236 }
237 Err(TwzError::NOT_FOUND)
238 }
239}