Skip to content

Commit 2eddc58

Browse files
run-make-support: add object-based symbol helpers
- `dynamic_symbol_names` - `text_section_global_dynamic_symbol_names` - `global_undefined_dynamic_symbol_names` Also add some missing `#[track_caller]` attributes. Co-authored-by: binarycat <binarycat@envs.net>
1 parent 7a55233 commit 2eddc58

File tree

1 file changed

+71
-5
lines changed

1 file changed

+71
-5
lines changed

src/tools/run-make-support/src/symbols.rs

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,84 @@
11
use std::path::Path;
22

3-
use object::{self, Object, ObjectSymbol, SymbolIterator};
3+
use object::{self, Object, ObjectSymbol, SectionIndex, SymbolIterator};
44

5-
/// Iterate through the symbols in an object file.
5+
/// Given an [`object::File`], find the dynamic symbol names via
6+
/// [`object::Object::dynamic_symbols`]. This does **not** impose any filters on the specific
7+
/// dynamic symbols, e.g. if they are global or local, if they are defined or not, and in which
8+
/// section the dynamic symbols reside in.
69
///
7-
/// Uses a callback because `SymbolIterator` does not own its data.
10+
/// On Windows, [`object::Object::dynamic_symbols`] will return an empty iterator because the symbol
11+
/// names are stored in a separate file (which object doesn't know how to read). Use
12+
/// [`object::Object::exports`] instead of this helper.
13+
#[track_caller]
14+
pub fn dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> Vec<&'file str> {
15+
file.dynamic_symbols().map(|sym| sym.name().unwrap()).collect()
16+
}
17+
18+
/// Given an [`object::File`], find the global (externally visible) dynamic symbol names in the
19+
/// `.text` section via [`object::Object::dynamic_symbols`]. This requires that `.text`'s section
20+
/// index is known.
21+
///
22+
/// On Windows, [`object::Object::dynamic_symbols`] will return an empty iterator because the symbol
23+
/// names are stored in a separate file (which object doesn't know how to read). Use
24+
/// [`object::Object::exports`] instead of this helper.
25+
///
26+
/// # Example
27+
///
28+
/// ```rust,no_run
29+
/// use object::{self, Object};
30+
/// use run_make_support::{rfs, dynamic_lib_name};
31+
///
32+
/// let dylib_filename = dynamic_lib_name("foo");
33+
/// let blob = rfs::read(&dylib_filename);
34+
/// let file = object::File::parse(&*blob)
35+
/// .unwrap_or_else(|e| panic!("failed to read `{dylib_filename}`: {e}"));
36+
/// let text_section =
37+
/// file.section_by_name(".text").expect("couldn't find `.text` section");
38+
/// let found_symbols = text_section_global_dynamic_symbol_names(&file, text_section.index());
39+
/// ```
40+
#[track_caller]
41+
pub fn text_section_global_dynamic_symbol_names<'file>(
42+
file: &'file object::File<'file>,
43+
text_section_idx: SectionIndex,
44+
) -> Vec<&'file str> {
45+
file.dynamic_symbols()
46+
.filter(|sym| {
47+
sym.is_global() && sym.section_index().is_some_and(|idx| idx == text_section_idx)
48+
})
49+
.map(|sym| sym.name().unwrap())
50+
.collect()
51+
}
52+
53+
/// Given an [`object::File`], find the global (externally visible) undefined dynamic symbol names
54+
/// in the `.text` section via [`object::Object::dynamic_symbols`].
55+
///
56+
/// On Windows, [`object::Object::dynamic_symbols`] will return an empty iterator because the symbol
57+
/// names are stored in a separate file (which object doesn't know how to read). Use
58+
/// [`object::Object::exports`] instead of this helper.
59+
#[track_caller]
60+
pub fn global_undefined_dynamic_symbol_names<'file>(
61+
file: &'file object::File<'file>,
62+
) -> Vec<&'file str> {
63+
file.dynamic_symbols()
64+
.filter(|sym| sym.is_global() && sym.is_undefined())
65+
.map(|sym| sym.name().unwrap())
66+
.collect()
67+
}
68+
69+
/// Iterate through the symbols in an object file. See [`object::Object::symbols`].
870
///
971
/// Panics if `path` is not a valid object file readable by the current user.
72+
#[track_caller]
1073
pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R
1174
where
1275
P: AsRef<Path>,
1376
F: FnOnce(&mut SymbolIterator<'_, '_>) -> R,
1477
{
15-
let raw_bytes = crate::fs::read(path);
16-
let f = object::File::parse(raw_bytes.as_slice()).expect("unable to parse file");
78+
let path = path.as_ref();
79+
let blob = crate::fs::read(path);
80+
let f = object::File::parse(&*blob)
81+
.unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display()));
1782
let mut iter = f.symbols();
1883
func(&mut iter)
1984
}
@@ -24,6 +89,7 @@ where
2489
/// `path` contain a substring listed in `substrings`.
2590
///
2691
/// Panics if `path` is not a valid object file readable by the current user.
92+
#[track_caller]
2793
pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool {
2894
with_symbol_iter(path, |syms| {
2995
for sym in syms {

0 commit comments

Comments
 (0)