1#![allow(clippy::missing_safety_doc)]
17#![allow(clippy::result_unit_err)]
18#![allow(clippy::type_complexity)]
19#![allow(clippy::too_many_arguments)]
20#![allow(clippy::needless_doctest_main)]
21#![doc(html_root_url = "https://dev-rust.binary.ninja/")]
22#![doc(html_favicon_url = "https://binary.ninja/icons/favicon-32x32.png")]
23#![doc(html_logo_url = "https://binary.ninja/icons/android-chrome-512x512.png")]
24#![doc(issue_tracker_base_url = "https://github.com/Vector35/binaryninja-api/issues/")]
25#![doc = include_str!("../README.md")]
26
27#[macro_use]
28mod ffi;
29
30pub mod architecture;
31pub mod background_task;
32pub mod base_detection;
33pub mod basic_block;
34pub mod binary_view;
35pub mod calling_convention;
36pub mod collaboration;
37pub mod command;
38pub mod component;
39pub mod confidence;
40pub mod data_buffer;
41pub mod data_notification;
42pub mod data_renderer;
43pub mod database;
44pub mod debuginfo;
45pub mod demangle;
46pub mod disassembly;
47pub mod download;
48pub mod enterprise;
49pub mod external_library;
50pub mod file_accessor;
51pub mod file_metadata;
52pub mod flowgraph;
53pub mod function;
54pub mod function_recognizer;
55pub mod headless;
56pub mod high_level_il;
57pub mod interaction;
58pub mod language_representation;
59pub mod line_formatter;
60pub mod linear_view;
61pub mod llvm;
62pub mod logger;
63pub mod low_level_il;
64pub mod main_thread;
65pub mod medium_level_il;
66pub mod metadata;
67pub mod object_destructor;
68pub mod platform;
69pub mod progress;
70pub mod project;
71pub mod qualified_name;
72pub mod rc;
73pub mod references;
74pub mod relocation;
75pub mod render_layer;
76pub mod repository;
77pub mod secrets_provider;
78pub mod section;
79pub mod segment;
80pub mod settings;
81pub mod string;
82pub mod string_detection;
83pub mod symbol;
84pub mod tags;
85pub mod template_simplifier;
86pub mod tracing;
87pub mod types;
88pub mod update;
89pub mod variable;
90pub mod websocket;
91pub mod worker_thread;
92pub mod workflow;
93
94use crate::progress::{NoProgressCallback, ProgressCallback};
95use crate::string::raw_to_string;
96use binary_view::BinaryView;
97use binaryninjacore_sys::*;
98use rc::Ref;
99use std::cmp;
100use std::collections::HashMap;
101use std::ffi::{c_char, c_void, CStr};
102use std::fmt::{Display, Formatter};
103use std::path::{Path, PathBuf};
104use string::BnString;
105use string::IntoCStr;
106use string::IntoJson;
107
108use crate::project::file::ProjectFile;
109pub use binaryninjacore_sys::BNDataFlowQueryOption as DataFlowQueryOption;
110pub use binaryninjacore_sys::BNEndianness as Endianness;
111pub use binaryninjacore_sys::BNILBranchDependence as ILBranchDependence;
112
113pub const BN_FULL_CONFIDENCE: u8 = u8::MAX;
114pub const BN_INVALID_EXPR: usize = usize::MAX;
115
116pub fn load(file_path: impl AsRef<Path>) -> Option<Ref<BinaryView>> {
118 load_with_progress(file_path, NoProgressCallback)
119}
120
121pub fn load_with_progress<P: ProgressCallback>(
125 file_path: impl AsRef<Path>,
126 mut progress: P,
127) -> Option<Ref<BinaryView>> {
128 let file_path = file_path.as_ref().to_cstr();
129 let options = c"";
130 let handle = unsafe {
131 BNLoadFilename(
132 file_path.as_ptr() as *mut _,
133 true,
134 options.as_ptr() as *mut c_char,
135 Some(P::cb_progress_callback),
136 &mut progress as *mut P as *mut c_void,
137 )
138 };
139
140 if handle.is_null() {
141 None
142 } else {
143 Some(unsafe { BinaryView::ref_from_raw(handle) })
144 }
145}
146
147pub fn load_with_options<O>(
165 file_path: impl AsRef<Path>,
166 update_analysis_and_wait: bool,
167 options: Option<O>,
168) -> Option<Ref<BinaryView>>
169where
170 O: IntoJson,
171{
172 load_with_options_and_progress(
173 file_path,
174 update_analysis_and_wait,
175 options,
176 NoProgressCallback,
177 )
178}
179
180pub fn load_with_options_and_progress<O, P>(
184 file_path: impl AsRef<Path>,
185 update_analysis_and_wait: bool,
186 options: Option<O>,
187 mut progress: P,
188) -> Option<Ref<BinaryView>>
189where
190 O: IntoJson,
191 P: ProgressCallback,
192{
193 let file_path = file_path.as_ref().to_cstr();
194 let options_or_default = if let Some(opt) = options {
195 opt.get_json_string()
196 .ok()?
197 .to_cstr()
198 .to_bytes_with_nul()
199 .to_vec()
200 } else {
201 "{}".to_cstr().to_bytes_with_nul().to_vec()
202 };
203 let handle = unsafe {
204 BNLoadFilename(
205 file_path.as_ptr() as *mut _,
206 update_analysis_and_wait,
207 options_or_default.as_ptr() as *mut c_char,
208 Some(P::cb_progress_callback),
209 &mut progress as *mut P as *mut c_void,
210 )
211 };
212
213 if handle.is_null() {
214 None
215 } else {
216 Some(unsafe { BinaryView::ref_from_raw(handle) })
217 }
218}
219
220pub fn load_view<O>(
221 bv: &BinaryView,
222 update_analysis_and_wait: bool,
223 options: Option<O>,
224) -> Option<Ref<BinaryView>>
225where
226 O: IntoJson,
227{
228 load_view_with_progress(bv, update_analysis_and_wait, options, NoProgressCallback)
229}
230
231pub fn load_view_with_progress<O, P>(
233 bv: &BinaryView,
234 update_analysis_and_wait: bool,
235 options: Option<O>,
236 mut progress: P,
237) -> Option<Ref<BinaryView>>
238where
239 O: IntoJson,
240 P: ProgressCallback,
241{
242 let options_or_default = if let Some(opt) = options {
243 opt.get_json_string()
244 .ok()?
245 .to_cstr()
246 .to_bytes_with_nul()
247 .to_vec()
248 } else {
249 "{}".to_cstr().to_bytes_with_nul().to_vec()
250 };
251 let handle = unsafe {
252 BNLoadBinaryView(
253 bv.handle as *mut _,
254 update_analysis_and_wait,
255 options_or_default.as_ptr() as *mut c_char,
256 Some(P::cb_progress_callback),
257 &mut progress as *mut P as *mut c_void,
258 )
259 };
260
261 if handle.is_null() {
262 None
263 } else {
264 Some(unsafe { BinaryView::ref_from_raw(handle) })
265 }
266}
267
268pub fn load_project_file<O>(
269 file: &ProjectFile,
270 update_analysis_and_wait: bool,
271 options: Option<O>,
272) -> Option<Ref<BinaryView>>
273where
274 O: IntoJson,
275{
276 load_project_file_with_progress(file, update_analysis_and_wait, options, NoProgressCallback)
277}
278
279pub fn load_project_file_with_progress<O, P>(
281 file: &ProjectFile,
282 update_analysis_and_wait: bool,
283 options: Option<O>,
284 mut progress: P,
285) -> Option<Ref<BinaryView>>
286where
287 O: IntoJson,
288 P: ProgressCallback,
289{
290 let options_or_default = if let Some(opt) = options {
291 opt.get_json_string()
292 .ok()?
293 .to_cstr()
294 .to_bytes_with_nul()
295 .to_vec()
296 } else {
297 "{}".to_cstr().to_bytes_with_nul().to_vec()
298 };
299 let handle = unsafe {
300 BNLoadProjectFile(
301 file.handle.as_ptr(),
302 update_analysis_and_wait,
303 options_or_default.as_ptr() as *mut c_char,
304 Some(P::cb_progress_callback),
305 &mut progress as *mut P as *mut c_void,
306 )
307 };
308
309 if handle.is_null() {
310 None
311 } else {
312 Some(unsafe { BinaryView::ref_from_raw(handle) })
313 }
314}
315
316pub fn install_directory() -> PathBuf {
317 let install_dir_ptr: *mut c_char = unsafe { BNGetInstallDirectory() };
318 assert!(!install_dir_ptr.is_null());
319 let install_dir_str = unsafe { BnString::into_string(install_dir_ptr) };
320 PathBuf::from(install_dir_str)
321}
322
323pub fn bundled_plugin_directory() -> Result<PathBuf, ()> {
324 let s: *mut c_char = unsafe { BNGetBundledPluginDirectory() };
325 if s.is_null() {
326 return Err(());
327 }
328 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
329}
330
331pub fn set_bundled_plugin_directory(new_dir: impl AsRef<Path>) {
332 let new_dir = new_dir.as_ref().to_cstr();
333 unsafe { BNSetBundledPluginDirectory(new_dir.as_ptr()) };
334}
335
336pub fn user_directory() -> PathBuf {
337 let user_dir_ptr: *mut c_char = unsafe { BNGetUserDirectory() };
338 assert!(!user_dir_ptr.is_null());
339 let user_dir_str = unsafe { BnString::into_string(user_dir_ptr) };
340 PathBuf::from(user_dir_str)
341}
342
343pub fn user_plugin_directory() -> Result<PathBuf, ()> {
344 let s: *mut c_char = unsafe { BNGetUserPluginDirectory() };
345 if s.is_null() {
346 return Err(());
347 }
348 let user_plugin_dir_str = unsafe { BnString::into_string(s) };
349 Ok(PathBuf::from(user_plugin_dir_str))
350}
351
352pub fn repositories_directory() -> Result<PathBuf, ()> {
353 let s: *mut c_char = unsafe { BNGetRepositoriesDirectory() };
354 if s.is_null() {
355 return Err(());
356 }
357 let repo_dir_str = unsafe { BnString::into_string(s) };
358 Ok(PathBuf::from(repo_dir_str))
359}
360
361pub fn settings_file_path() -> PathBuf {
362 let settings_file_name_ptr: *mut c_char = unsafe { BNGetSettingsFileName() };
363 assert!(!settings_file_name_ptr.is_null());
364 let settings_file_path_str = unsafe { BnString::into_string(settings_file_name_ptr) };
365 PathBuf::from(settings_file_path_str)
366}
367
368pub fn save_last_run() {
372 unsafe { BNSaveLastRun() };
373}
374
375pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
376 let path_raw = path.as_ref().to_cstr();
377 let s: *mut c_char = unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr()) };
378 if s.is_null() {
379 return Err(());
380 }
381 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
382}
383
384pub fn path_relative_to_user_plugin_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
385 let path_raw = path.as_ref().to_cstr();
386 let s: *mut c_char = unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr()) };
387 if s.is_null() {
388 return Err(());
389 }
390 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
391}
392
393pub fn path_relative_to_user_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
394 let path_raw = path.as_ref().to_cstr();
395 let s: *mut c_char = unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr()) };
396 if s.is_null() {
397 return Err(());
398 }
399 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
400}
401
402pub fn is_main_thread() -> bool {
406 unsafe { BNIsMainThread() }
407}
408
409pub fn memory_info() -> HashMap<String, u64> {
410 let mut count = 0;
411 let mut usage = HashMap::new();
412 unsafe {
413 let info_ptr = BNGetMemoryUsageInfo(&mut count);
414 let info_list = std::slice::from_raw_parts(info_ptr, count);
415 for info in info_list {
416 let info_name = CStr::from_ptr(info.name).to_str().unwrap().to_string();
417 usage.insert(info_name, info.value);
418 }
419 BNFreeMemoryUsageInfo(info_ptr, count);
420 }
421 usage
422}
423
424pub fn version() -> String {
425 unsafe { BnString::into_string(BNGetVersionString()) }
426}
427
428pub fn build_id() -> u32 {
429 unsafe { BNGetBuildId() }
430}
431
432#[derive(Clone, PartialEq, Eq, Hash, Debug)]
433pub struct VersionInfo {
434 pub major: u32,
435 pub minor: u32,
436 pub build: u32,
437 pub channel: String,
438}
439
440impl VersionInfo {
441 pub(crate) fn from_raw(value: &BNVersionInfo) -> Self {
442 Self {
443 major: value.major,
444 minor: value.minor,
445 build: value.build,
446 channel: raw_to_string(value.channel).unwrap_or_default(),
448 }
449 }
450
451 pub(crate) fn from_owned_raw(value: BNVersionInfo) -> Self {
452 let owned = Self::from_raw(&value);
453 Self::free_raw(value);
454 owned
455 }
456
457 pub(crate) fn into_owned_raw(value: &Self) -> BNVersionInfo {
458 BNVersionInfo {
459 major: value.major,
460 minor: value.minor,
461 build: value.build,
462 channel: value.channel.as_ptr() as *mut c_char,
463 }
464 }
465
466 pub(crate) fn free_raw(value: BNVersionInfo) {
467 unsafe { BnString::free_raw(value.channel) };
468 }
469}
470
471impl TryFrom<&str> for VersionInfo {
472 type Error = ();
473
474 fn try_from(value: &str) -> Result<Self, Self::Error> {
475 let string = value.to_cstr();
476 let result = unsafe { BNParseVersionString(string.as_ptr()) };
477 if result.build == 0 && result.channel.is_null() && result.major == 0 && result.minor == 0 {
478 return Err(());
479 }
480 Ok(Self::from_owned_raw(result))
481 }
482}
483
484impl PartialOrd for VersionInfo {
485 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
486 Some(self.cmp(other))
487 }
488}
489
490impl Ord for VersionInfo {
491 fn cmp(&self, other: &Self) -> cmp::Ordering {
492 if self == other {
493 return cmp::Ordering::Equal;
494 }
495 let bn_version_0 = VersionInfo::into_owned_raw(self);
496 let bn_version_1 = VersionInfo::into_owned_raw(other);
497 if unsafe { BNVersionLessThan(bn_version_0, bn_version_1) } {
498 cmp::Ordering::Less
499 } else {
500 cmp::Ordering::Greater
501 }
502 }
503}
504
505impl Display for VersionInfo {
506 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
507 if self.channel.is_empty() {
508 write!(f, "{}.{}.{}", self.major, self.minor, self.build)
509 } else {
510 write!(
511 f,
512 "{}.{}.{}-{}",
513 self.major, self.minor, self.build, self.channel
514 )
515 }
516 }
517}
518
519pub fn version_info() -> VersionInfo {
520 let info_raw = unsafe { BNGetVersionInfo() };
521 VersionInfo::from_owned_raw(info_raw)
522}
523
524pub fn serial_number() -> String {
525 unsafe { BnString::into_string(BNGetSerialNumber()) }
526}
527
528pub fn is_license_validated() -> bool {
529 unsafe { BNIsLicenseValidated() }
530}
531
532pub fn licensed_user_email() -> String {
533 unsafe { BnString::into_string(BNGetLicensedUserEmail()) }
534}
535
536pub fn license_path() -> PathBuf {
537 user_directory().join("license.dat")
538}
539
540pub fn license_count() -> i32 {
541 unsafe { BNGetLicenseCount() }
542}
543
544#[cfg(not(feature = "demo"))]
550pub fn set_license(license: Option<&str>) {
551 let license = license.unwrap_or_default().to_cstr();
552 unsafe { BNSetLicense(license.as_ptr()) }
553}
554
555#[cfg(feature = "demo")]
556pub fn set_license(_license: Option<&str>) {}
557
558pub fn product() -> String {
559 unsafe { BnString::into_string(BNGetProduct()) }
560}
561
562pub fn product_type() -> String {
563 unsafe { BnString::into_string(BNGetProductType()) }
564}
565
566pub fn license_expiration_time() -> std::time::SystemTime {
567 let m = std::time::Duration::from_secs(unsafe { BNGetLicenseExpirationTime() });
568 std::time::UNIX_EPOCH + m
569}
570
571pub fn is_ui_enabled() -> bool {
572 unsafe { BNIsUIEnabled() }
573}
574
575pub fn is_database(file: &Path) -> bool {
576 let filename = file.to_cstr();
577 unsafe { BNIsDatabase(filename.as_ptr()) }
578}
579
580pub fn plugin_abi_version() -> u32 {
581 BN_CURRENT_CORE_ABI_VERSION
582}
583
584pub fn plugin_abi_minimum_version() -> u32 {
585 BN_MINIMUM_CORE_ABI_VERSION
586}
587
588pub fn core_abi_version() -> u32 {
589 unsafe { BNGetCurrentCoreABIVersion() }
590}
591
592pub fn core_abi_minimum_version() -> u32 {
593 unsafe { BNGetMinimumCoreABIVersion() }
594}
595
596pub fn plugin_ui_abi_version() -> u32 {
597 BN_CURRENT_UI_ABI_VERSION
598}
599
600pub fn plugin_ui_abi_minimum_version() -> u32 {
601 BN_MINIMUM_UI_ABI_VERSION
602}
603
604pub fn add_required_plugin_dependency(name: &str) {
605 let raw_name = name.to_cstr();
606 unsafe { BNAddRequiredPluginDependency(raw_name.as_ptr()) };
607}
608
609pub fn add_optional_plugin_dependency(name: &str) {
610 let raw_name = name.to_cstr();
611 unsafe { BNAddOptionalPluginDependency(raw_name.as_ptr()) };
612}
613
614#[cfg(not(feature = "no_exports"))]
616#[no_mangle]
617#[allow(non_snake_case)]
618pub extern "C" fn CorePluginABIVersion() -> u32 {
619 plugin_abi_version()
620}
621
622#[cfg(not(feature = "no_exports"))]
624#[no_mangle]
625pub extern "C" fn UIPluginABIVersion() -> u32 {
626 plugin_ui_abi_version()
627}