run_make_support/
symbols.rs1use std::collections::BTreeSet;
2use std::path::Path;
3
4use object::{self, Object, ObjectSymbol};
5
6#[track_caller]
10pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> Vec<&'file str> {
11 file.exports()
12 .unwrap()
13 .into_iter()
14 .filter_map(|sym| std::str::from_utf8(sym.name()).ok())
15 .collect()
16}
17
18#[track_caller]
34pub fn object_contains_any_symbol_substring<P, S>(path: P, substrings: &[S]) -> bool
35where
36 P: AsRef<Path>,
37 S: AsRef<str>,
38{
39 let path = path.as_ref();
40 let blob = crate::fs::read(path);
41 let obj = object::File::parse(&*blob)
42 .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
43 let substrings = substrings.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
44 for sym in obj.symbols() {
45 for substring in &substrings {
46 if sym.name_bytes().unwrap().windows(substring.len()).any(|x| x == substring.as_bytes())
47 {
48 return true;
49 }
50 }
51 }
52 false
53}
54
55#[track_caller]
69pub fn object_contains_any_symbol<P, S>(path: P, candidate_symbols: &[S]) -> bool
70where
71 P: AsRef<Path>,
72 S: AsRef<str>,
73{
74 let path = path.as_ref();
75 let blob = crate::fs::read(path);
76 let obj = object::File::parse(&*blob)
77 .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
78 let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
79 for sym in obj.symbols() {
80 for candidate_symbol in &candidate_symbols {
81 if sym.name_bytes().unwrap() == candidate_symbol.as_bytes() {
82 return true;
83 }
84 }
85 }
86 false
87}
88
89#[derive(Debug, PartialEq)]
90pub enum ContainsAllSymbolSubstringsOutcome<'a> {
91 Ok,
92 MissingSymbolSubstrings(BTreeSet<&'a str>),
93}
94
95#[track_caller]
110pub fn object_contains_all_symbol_substring<'s, P, S>(
111 path: P,
112 substrings: &'s [S],
113) -> ContainsAllSymbolSubstringsOutcome<'s>
114where
115 P: AsRef<Path>,
116 S: AsRef<str>,
117{
118 let path = path.as_ref();
119 let blob = crate::fs::read(path);
120 let obj = object::File::parse(&*blob)
121 .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
122 let substrings = substrings.iter().map(|s| s.as_ref());
123 let mut unmatched_symbol_substrings = BTreeSet::from_iter(substrings);
124 unmatched_symbol_substrings.retain(|unmatched_symbol_substring| {
125 for sym in obj.symbols() {
126 if sym
127 .name_bytes()
128 .unwrap()
129 .windows(unmatched_symbol_substring.len())
130 .any(|x| x == unmatched_symbol_substring.as_bytes())
131 {
132 return false;
133 }
134 }
135
136 true
137 });
138
139 if unmatched_symbol_substrings.is_empty() {
140 ContainsAllSymbolSubstringsOutcome::Ok
141 } else {
142 ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(unmatched_symbol_substrings)
143 }
144}
145
146#[derive(Debug, PartialEq)]
147pub enum ContainsAllSymbolsOutcome<'a> {
148 Ok,
149 MissingSymbols(BTreeSet<&'a str>),
150}
151
152#[track_caller]
165pub fn object_contains_all_symbols<P, S>(
166 path: P,
167 candidate_symbols: &[S],
168) -> ContainsAllSymbolsOutcome<'_>
169where
170 P: AsRef<Path>,
171 S: AsRef<str>,
172{
173 let path = path.as_ref();
174 let blob = crate::fs::read(path);
175 let obj = object::File::parse(&*blob)
176 .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
177 let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref());
178 let mut unmatched_symbols = BTreeSet::from_iter(candidate_symbols);
179 unmatched_symbols.retain(|unmatched_symbol| {
180 for sym in obj.symbols() {
181 if sym.name_bytes().unwrap() == unmatched_symbol.as_bytes() {
182 return false;
183 }
184 }
185
186 true
187 });
188
189 if unmatched_symbols.is_empty() {
190 ContainsAllSymbolsOutcome::Ok
191 } else {
192 ContainsAllSymbolsOutcome::MissingSymbols(unmatched_symbols)
193 }
194}