1use super::{Context, LoadedOrUnloaded};
2use crate::{
3 library::{Library, LibraryId},
4 symbol::{LookupFlags, RelocatedSymbol},
5 DynlinkError, DynlinkErrorKind,
6};
7
8impl Context {
9 pub fn lookup_symbol<'a>(
13 &'a self,
14 start_id: LibraryId,
15 name: &str,
16 lookup_flags: LookupFlags,
17 ) -> Result<RelocatedSymbol<'a>, DynlinkError> {
18 let allow_weak = lookup_flags.contains(LookupFlags::ALLOW_WEAK);
19 let start_lib = self.get_library(start_id)?;
20 if !lookup_flags.contains(LookupFlags::SKIP_SELF) {
22 if let Ok(sym) = start_lib.lookup_symbol(name, allow_weak, false) {
23 return Ok(sym);
24 }
25 }
26
27 if !lookup_flags.contains(LookupFlags::SKIP_DEPS) {
29 let mut visit = petgraph::visit::Bfs::new(&self.library_deps, start_id.0);
30 while let Some(node) = visit.next(&self.library_deps) {
31 let dep = &self.library_deps[node];
32 if node != start_id.0 {
33 match dep {
34 LoadedOrUnloaded::Unloaded(_) => {}
35 LoadedOrUnloaded::Loaded(dep) => {
36 if lookup_flags.contains(LookupFlags::SKIP_SECGATE_CHECK)
37 || dep.is_local_or_secgate_from(start_lib, name)
38 {
39 let allow_weak =
40 allow_weak && dep.in_same_compartment_as(start_lib);
41 let try_prefix =
42 dep.in_same_compartment_as(start_lib) || dep.allows_gates();
43 if let Ok(sym) = dep.lookup_symbol(name, allow_weak, try_prefix) {
44 return Ok(sym);
45 }
46 }
47 }
48 }
49 }
50 }
51 }
52
53 if !lookup_flags.contains(LookupFlags::SKIP_GLOBAL) {
55 tracing::trace!("falling back to global search for {}", name);
56
57 let res = self.lookup_symbol_global(start_lib, name, lookup_flags);
58 if res.is_ok() {
59 return res;
60 }
61
62 if !allow_weak {
63 let res =
64 self.lookup_symbol(start_id, name, lookup_flags.union(LookupFlags::ALLOW_WEAK));
65 if res.is_ok() {
66 return res;
67 }
68 }
69 }
70 Err(DynlinkErrorKind::NameNotFound {
71 name: name.to_string(),
72 }
73 .into())
74 }
75
76 pub(crate) fn lookup_symbol_global<'a>(
77 &'a self,
78 start_lib: &Library,
79 name: &str,
80 lookup_flags: LookupFlags,
81 ) -> Result<RelocatedSymbol<'a>, DynlinkError> {
82 for idx in self.library_deps.node_indices() {
83 let dep = &self.library_deps[idx];
84 match dep {
85 LoadedOrUnloaded::Unloaded(_) => {}
86 LoadedOrUnloaded::Loaded(dep) => {
87 if lookup_flags.contains(LookupFlags::SKIP_SECGATE_CHECK)
88 || dep.is_local_or_secgate_from(start_lib, name)
89 {
90 let allow_weak = lookup_flags.contains(LookupFlags::ALLOW_WEAK)
91 && dep.in_same_compartment_as(start_lib);
92 let try_prefix = (idx != start_lib.id().0 || dep.allows_self_gates())
93 && (dep.allows_gates() || dep.in_same_compartment_as(start_lib));
94 if let Ok(sym) = dep.lookup_symbol(name, allow_weak, try_prefix) {
95 return Ok(sym);
96 }
97 }
98 }
99 }
100 }
101 Err(DynlinkErrorKind::NameNotFound {
102 name: name.to_string(),
103 }
104 .into())
105 }
106}