1
0
Fork 0

Add a bundler module for parsing exported symbols

We can use this to detect which plugin formats are supported by a
plugin. Otherwise the bundler would be very awkward to use when
supporting multiple formats.
This commit is contained in:
Robbert van der Helm 2022-02-26 19:58:30 +01:00
parent fefc2de9ba
commit d39ebb5b51
4 changed files with 72 additions and 0 deletions

38
Cargo.lock generated
View file

@ -400,6 +400,17 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "goblin"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c955ab4e0ad8c843ea653a3d143048b87490d9be56bd7132a435c2407846ac8f"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.1" version = "1.0.1"
@ -665,6 +676,12 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.36"
@ -728,6 +745,26 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scroll"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.136" version = "1.0.136"
@ -1118,6 +1155,7 @@ name = "xtask"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"goblin",
"serde", "serde",
"toml", "toml",
] ]

View file

@ -7,5 +7,6 @@ license = "ISC"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
goblin = "0.5"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5" toml = "0.5"

View file

@ -5,6 +5,8 @@ use std::fs;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
mod symbols;
const USAGE_STRING: &str = const USAGE_STRING: &str =
"Usage: cargo xtask bundle <package> [--release] [--target <triple>] [--bundle-vst3]"; "Usage: cargo xtask bundle <package> [--release] [--target <triple>] [--bundle-vst3]";

31
xtask/src/symbols.rs Normal file
View file

@ -0,0 +1,31 @@
use anyhow::{bail, Context, Result};
use std::fs;
use std::path::Path;
/// Check whether a binary exports the specified symbol. Used to detect the plugin formats supported
/// by a plugin library. Returns an error if the binary cuuld not be read. This function will also
/// parse non-native binaries.
pub fn exported<P: AsRef<Path>>(binary: P, symbol: &str) -> Result<bool> {
// Parsing the raw binary instead of relying on nm-like tools makes cross compiling a bit easier
let bytes = fs::read(&binary)
.with_context(|| format!("Could not read '{}'", binary.as_ref().display()))?;
match goblin::Object::parse(&bytes)? {
goblin::Object::Elf(obj) => Ok(obj.dynsyms.iter().any(|sym| {
!sym.is_import()
&& sym.is_function()
&& obj.dynstrtab.get_at(sym.st_name) == Some(symbol)
})),
goblin::Object::Mach(obj) => {
let obj = match obj {
goblin::mach::Mach::Fat(arches) => arches
.get(0)
.context("Fat Mach-O binary without any binaries")?,
goblin::mach::Mach::Binary(obj) => obj,
};
Ok(obj.exports()?.into_iter().any(|sym| sym.name == symbol))
}
goblin::Object::PE(obj) => Ok(obj.exports.iter().any(|sym| sym.name == Some(symbol))),
obj => bail!("Unsupported object type: {:?}", obj),
}
}