ofps/plugins/
util.rs

1use anyhow::Result;
2
3use std::path::Path;
4
5#[cfg(not(any(target_os = "windows", target_os = "macos")))]
6pub fn find_export_by_prefix(path: impl AsRef<Path>, prefix: &str) -> Result<Vec<String>> {
7    use goblin::elf::Elf;
8
9    let buffer = std::fs::read(path.as_ref())?;
10    let elf = Elf::parse(buffer.as_slice())?;
11
12    Ok(elf
13        .syms
14        .iter()
15        .filter_map(|s| {
16            if let Some(name) = elf.strtab.get_at(s.st_name) {
17                match name.starts_with(prefix) {
18                    true => Some(name.to_owned()),
19                    false => None,
20                }
21            } else {
22                None
23            }
24        })
25        .collect::<Vec<_>>())
26}
27
28#[cfg(target_os = "windows")]
29pub fn find_export_by_prefix(path: impl AsRef<Path>, prefix: &str) -> Result<Vec<String>> {
30    use goblin::pe::PE;
31
32    let buffer = std::fs::read(path.as_ref())?;
33    let pe = PE::parse(buffer.as_slice())?;
34
35    Ok(pe
36        .exports
37        .iter()
38        .filter_map(|s| s.name)
39        .filter_map(|name| {
40            if name.starts_with(prefix) {
41                Some(name.to_owned())
42            } else {
43                None
44            }
45        })
46        .collect::<Vec<_>>())
47}
48
49#[cfg(target_os = "macos")]
50pub fn find_export_by_prefix(path: impl AsRef<Path>, prefix: &str) -> Result<Vec<String>> {
51    use goblin::mach::Mach;
52
53    let buffer = std::fs::read(path.as_ref())?;
54    let mach = Mach::parse(buffer.as_slice())?;
55
56    let macho = match mach {
57        Mach::Binary(mach) => mach,
58        Mach::Fat(mach) => (0..mach.narches)
59            .filter_map(|i| mach.get(i).ok())
60            .next()
61            .ok_or_else(|| anyhow::anyhow!("failed to find valid MachO header!"))?,
62    };
63
64    // macho symbols are prefixed with `_` in the object file.
65    let macho_prefix = "_".to_owned() + prefix;
66    Ok(macho
67        .symbols
68        .ok_or_else(|| anyhow::anyhow!("failed to parse MachO symbols!"))?
69        .iter()
70        .filter_map(|s| s.ok())
71        .filter_map(|(name, _)| {
72            // symbols should only contain ascii characters
73            if name.starts_with(&macho_prefix) {
74                Some(name[1..].to_owned())
75            } else {
76                None
77            }
78        })
79        .collect::<Vec<_>>())
80}