1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::PathBuf;
#[cfg(target_os = "macos")]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
#[cfg(target_os = "linux")]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
fn link_path() -> PathBuf {
use std::io::prelude::*;
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
File::open(lastrun)
.and_then(|f| {
let mut binja_path = String::new();
let mut reader = BufReader::new(f);
reader.read_line(&mut binja_path)?;
Ok(PathBuf::from(binja_path.trim()))
})
.unwrap_or_else(|_| {
#[cfg(target_os = "macos")]
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
#[cfg(target_os = "linux")]
return home.join("binaryninja");
#[cfg(windows)]
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
.join("Vector35\\BinaryNinja\\");
})
}
// Generate and compile stub shared library and return the path to the folder containing the built stub library
fn generate_stubs() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let api_base_path = std::path::PathBuf::from(manifest_dir)
.join("../../")
.canonicalize()
.unwrap();
let stubs_path = api_base_path.join("stubs");
// TODO: does visual studio add the config name as a subdirectory?
cmake::Config::new(stubs_path)
.generator("Ninja")
.build()
.join("build")
}
fn main() {
println!("cargo:rerun-if-env-changed=BINARYNINJADIR");
println!("cargo:rerun-if-changed=../../binaryninjacore.h");
//Cargo's output directory
let out_dir = env::var("OUT_DIR").unwrap();
let link_path = match env::var("CARGO_FEATURE_CORE") {
Ok(_) => env::var("BINARYNINJADIR")
.map(PathBuf::from)
.unwrap_or_else(|_| link_path()),
Err(_) => generate_stubs(),
};
// Linux builds of binaryninja ship with libbinaryninjacore.so.1 in the
// application folder and no symlink. The linker will attempt to link with
// libbinaryninjacore.so. Since this is likely going to fail, we detect this
// ahead of time and create an appropriately named symlink inside of OUT_DIR
// and add it to the library search path.
#[cfg(target_os = "linux")]
{
let symlink_source = PathBuf::from(&out_dir).join("libbinaryninjacore.so");
let symlink_target = link_path.join("libbinaryninjacore.so.1");
// Make a symlink "libbinaryninjacore.so" pointing to "libbinaryninjacore.so.1"
if symlink_target.exists() && symlink_source.symlink_metadata().is_err() {
use std::os::unix::fs;
fs::symlink(symlink_target, symlink_source).expect("failed to create required symlink");
}
println!("cargo:rustc-link-search={}", out_dir);
}
// Emit the path to binaryninjacore consumers of this crate should pass to the linker.
println!("cargo:path={}", link_path.to_str().unwrap());
let current_line = "#define BN_CURRENT_UI_ABI_VERSION ";
let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION ";
let mut current_version = "0".to_string();
let mut minimum_version = "0".to_string();
let file = File::open("../../ui/uitypes.h").expect("Couldn't open uitypes.h");
for line in BufReader::new(file).lines() {
let line = line.unwrap();
if let Some(version) = line.strip_prefix(current_line) {
version.clone_into(&mut current_version);
} else if let Some(version) = line.strip_prefix(minimum_line) {
version.clone_into(&mut minimum_version);
}
}
bindgen::builder()
.header("../../binaryninjacore.h")
.clang_arg("-std=c++20")
.clang_arg("-x")
.clang_arg("c++")
.size_t_is_usize(true)
.generate_comments(false)
.derive_default(true)
.generate_comments(true)
.clang_arg("-fparse-all-comments")
.allowlist_function("BN.*")
.allowlist_var("BN_CURRENT_CORE_ABI_VERSION")
.allowlist_var("BN_MINIMUM_CORE_ABI_VERSION")
.allowlist_var("MAX_RELOCATION_SIZE")
.raw_line(format!(
"pub const BN_CURRENT_UI_ABI_VERSION: u32 = {};",
current_version
))
.raw_line(format!(
"pub const BN_MINIMUM_UI_ABI_VERSION: u32 = {};",
minimum_version
))
.rustified_enum("BN.*")
.generate()
.expect("Unable to generate bindings")
.write_to_file(PathBuf::from(out_dir).join("bindings.rs"))
.expect("Couldn't write bindings!");
}
|