|
1 | 1 | use std::path::Path;
|
2 | 2 |
|
3 |
| -use object::{self, Object, ObjectSymbol, SymbolIterator}; |
| 3 | +use object::{self, Object, ObjectSymbol, SectionIndex, SymbolIterator}; |
4 | 4 |
|
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. |
6 | 9 | ///
|
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`]. |
8 | 70 | ///
|
9 | 71 | /// Panics if `path` is not a valid object file readable by the current user.
|
| 72 | +#[track_caller] |
10 | 73 | pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R
|
11 | 74 | where
|
12 | 75 | P: AsRef<Path>,
|
13 | 76 | F: FnOnce(&mut SymbolIterator<'_, '_>) -> R,
|
14 | 77 | {
|
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())); |
17 | 82 | let mut iter = f.symbols();
|
18 | 83 | func(&mut iter)
|
19 | 84 | }
|
|
24 | 89 | /// `path` contain a substring listed in `substrings`.
|
25 | 90 | ///
|
26 | 91 | /// Panics if `path` is not a valid object file readable by the current user.
|
| 92 | +#[track_caller] |
27 | 93 | pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool {
|
28 | 94 | with_symbol_iter(path, |syms| {
|
29 | 95 | for sym in syms {
|
|
0 commit comments