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 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 if name.starts_with(&macho_prefix) {
74 Some(name[1..].to_owned())
75 } else {
76 None
77 }
78 })
79 .collect::<Vec<_>>())
80}