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