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 custom_binary_view;
41pub mod data_buffer;
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 platform;
68pub mod progress;
69pub mod project;
70pub mod rc;
71pub mod references;
72pub mod relocation;
73pub mod render_layer;
74pub mod repository;
75pub mod secrets_provider;
76pub mod section;
77pub mod segment;
78pub mod settings;
79pub mod string;
80pub mod symbol;
81pub mod tags;
82pub mod template_simplifier;
83pub mod type_archive;
84pub mod type_container;
85pub mod type_library;
86pub mod type_parser;
87pub mod type_printer;
88pub mod types;
89pub mod update;
90pub mod variable;
91pub mod websocket;
92pub mod worker_thread;
93pub mod workflow;
94
95use crate::file_metadata::FileMetadata;
96use crate::function::Function;
97use binary_view::BinaryView;
98use binaryninjacore_sys::*;
99use metadata::Metadata;
100use metadata::MetadataType;
101use rc::Ref;
102use std::cmp;
103use std::collections::HashMap;
104use std::ffi::{c_char, c_void, CStr};
105use std::path::{Path, PathBuf};
106use string::BnString;
107use string::IntoCStr;
108use string::IntoJson;
109
110use crate::progress::{NoProgressCallback, ProgressCallback};
111use crate::string::raw_to_string;
112pub use binaryninjacore_sys::BNBranchType as BranchType;
113pub use binaryninjacore_sys::BNDataFlowQueryOption as DataFlowQueryOption;
114pub use binaryninjacore_sys::BNEndianness as Endianness;
115pub use binaryninjacore_sys::BNILBranchDependence as ILBranchDependence;
116
117pub const BN_FULL_CONFIDENCE: u8 = u8::MAX;
118pub const BN_INVALID_EXPR: usize = usize::MAX;
119
120pub fn load(file_path: impl AsRef<Path>) -> Option<Ref<BinaryView>> {
122 load_with_progress(file_path, NoProgressCallback)
123}
124
125pub fn load_with_progress<P: ProgressCallback>(
129 file_path: impl AsRef<Path>,
130 mut progress: P,
131) -> Option<Ref<BinaryView>> {
132 let file_path = file_path.as_ref().to_cstr();
133 let options = c"";
134 let handle = unsafe {
135 BNLoadFilename(
136 file_path.as_ptr() as *mut _,
137 true,
138 options.as_ptr() as *mut c_char,
139 Some(P::cb_progress_callback),
140 &mut progress as *mut P as *mut c_void,
141 )
142 };
143
144 if handle.is_null() {
145 None
146 } else {
147 Some(unsafe { BinaryView::ref_from_raw(handle) })
148 }
149}
150
151pub fn load_with_options<O>(
169 file_path: impl AsRef<Path>,
170 update_analysis_and_wait: bool,
171 options: Option<O>,
172) -> Option<Ref<BinaryView>>
173where
174 O: IntoJson,
175{
176 load_with_options_and_progress(
177 file_path,
178 update_analysis_and_wait,
179 options,
180 NoProgressCallback,
181 )
182}
183
184pub fn load_with_options_and_progress<O, P>(
188 file_path: impl AsRef<Path>,
189 update_analysis_and_wait: bool,
190 options: Option<O>,
191 mut progress: P,
192) -> Option<Ref<BinaryView>>
193where
194 O: IntoJson,
195 P: ProgressCallback,
196{
197 let file_path = file_path.as_ref().to_cstr();
198 let options_or_default = if let Some(opt) = options {
199 opt.get_json_string()
200 .ok()?
201 .to_cstr()
202 .to_bytes_with_nul()
203 .to_vec()
204 } else {
205 Metadata::new_of_type(MetadataType::KeyValueDataType)
206 .get_json_string()
207 .ok()?
208 .as_ref()
209 .to_vec()
210 };
211 let handle = unsafe {
212 BNLoadFilename(
213 file_path.as_ptr() as *mut _,
214 update_analysis_and_wait,
215 options_or_default.as_ptr() as *mut c_char,
216 Some(P::cb_progress_callback),
217 &mut progress as *mut P as *mut c_void,
218 )
219 };
220
221 if handle.is_null() {
222 None
223 } else {
224 Some(unsafe { BinaryView::ref_from_raw(handle) })
225 }
226}
227
228pub fn load_view<O>(
229 bv: &BinaryView,
230 update_analysis_and_wait: bool,
231 options: Option<O>,
232) -> Option<Ref<BinaryView>>
233where
234 O: IntoJson,
235{
236 load_view_with_progress(bv, update_analysis_and_wait, options, NoProgressCallback)
237}
238
239pub fn load_view_with_progress<O, P>(
241 bv: &BinaryView,
242 update_analysis_and_wait: bool,
243 options: Option<O>,
244 mut progress: P,
245) -> Option<Ref<BinaryView>>
246where
247 O: IntoJson,
248 P: ProgressCallback,
249{
250 let options_or_default = if let Some(opt) = options {
251 opt.get_json_string()
252 .ok()?
253 .to_cstr()
254 .to_bytes_with_nul()
255 .to_vec()
256 } else {
257 Metadata::new_of_type(MetadataType::KeyValueDataType)
258 .get_json_string()
259 .ok()?
260 .as_ref()
261 .to_vec()
262 };
263 let handle = unsafe {
264 BNLoadBinaryView(
265 bv.handle as *mut _,
266 update_analysis_and_wait,
267 options_or_default.as_ptr() as *mut c_char,
268 Some(P::cb_progress_callback),
269 &mut progress as *mut P as *mut c_void,
270 )
271 };
272
273 if handle.is_null() {
274 None
275 } else {
276 Some(unsafe { BinaryView::ref_from_raw(handle) })
277 }
278}
279
280pub fn install_directory() -> PathBuf {
281 let install_dir_ptr: *mut c_char = unsafe { BNGetInstallDirectory() };
282 assert!(!install_dir_ptr.is_null());
283 let install_dir_str = unsafe { BnString::into_string(install_dir_ptr) };
284 PathBuf::from(install_dir_str)
285}
286
287pub fn bundled_plugin_directory() -> Result<PathBuf, ()> {
288 let s: *mut c_char = unsafe { BNGetBundledPluginDirectory() };
289 if s.is_null() {
290 return Err(());
291 }
292 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
293}
294
295pub fn set_bundled_plugin_directory(new_dir: impl AsRef<Path>) {
296 let new_dir = new_dir.as_ref().to_cstr();
297 unsafe { BNSetBundledPluginDirectory(new_dir.as_ptr()) };
298}
299
300pub fn user_directory() -> PathBuf {
301 let user_dir_ptr: *mut c_char = unsafe { BNGetUserDirectory() };
302 assert!(!user_dir_ptr.is_null());
303 let user_dir_str = unsafe { BnString::into_string(user_dir_ptr) };
304 PathBuf::from(user_dir_str)
305}
306
307pub fn user_plugin_directory() -> Result<PathBuf, ()> {
308 let s: *mut c_char = unsafe { BNGetUserPluginDirectory() };
309 if s.is_null() {
310 return Err(());
311 }
312 let user_plugin_dir_str = unsafe { BnString::into_string(s) };
313 Ok(PathBuf::from(user_plugin_dir_str))
314}
315
316pub fn repositories_directory() -> Result<PathBuf, ()> {
317 let s: *mut c_char = unsafe { BNGetRepositoriesDirectory() };
318 if s.is_null() {
319 return Err(());
320 }
321 let repo_dir_str = unsafe { BnString::into_string(s) };
322 Ok(PathBuf::from(repo_dir_str))
323}
324
325pub fn settings_file_path() -> PathBuf {
326 let settings_file_name_ptr: *mut c_char = unsafe { BNGetSettingsFileName() };
327 assert!(!settings_file_name_ptr.is_null());
328 let settings_file_path_str = unsafe { BnString::into_string(settings_file_name_ptr) };
329 PathBuf::from(settings_file_path_str)
330}
331
332pub fn save_last_run() {
336 unsafe { BNSaveLastRun() };
337}
338
339pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
340 let path_raw = path.as_ref().to_cstr();
341 let s: *mut c_char = unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr()) };
342 if s.is_null() {
343 return Err(());
344 }
345 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
346}
347
348pub fn path_relative_to_user_plugin_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
349 let path_raw = path.as_ref().to_cstr();
350 let s: *mut c_char = unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr()) };
351 if s.is_null() {
352 return Err(());
353 }
354 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
355}
356
357pub fn path_relative_to_user_directory(path: impl AsRef<Path>) -> Result<PathBuf, ()> {
358 let path_raw = path.as_ref().to_cstr();
359 let s: *mut c_char = unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr()) };
360 if s.is_null() {
361 return Err(());
362 }
363 Ok(PathBuf::from(unsafe { BnString::into_string(s) }))
364}
365
366pub fn is_main_thread() -> bool {
370 unsafe { BNIsMainThread() }
371}
372
373pub fn memory_info() -> HashMap<String, u64> {
374 let mut count = 0;
375 let mut usage = HashMap::new();
376 unsafe {
377 let info_ptr = BNGetMemoryUsageInfo(&mut count);
378 let info_list = std::slice::from_raw_parts(info_ptr, count);
379 for info in info_list {
380 let info_name = CStr::from_ptr(info.name).to_str().unwrap().to_string();
381 usage.insert(info_name, info.value);
382 }
383 BNFreeMemoryUsageInfo(info_ptr, count);
384 }
385 usage
386}
387
388pub trait ObjectDestructor: 'static + Sync + Sized {
390 fn destruct_view(&self, _view: &BinaryView) {}
391 fn destruct_file_metadata(&self, _metadata: &FileMetadata) {}
392 fn destruct_function(&self, _func: &Function) {}
393
394 unsafe extern "C" fn cb_destruct_binary_view(ctxt: *mut c_void, view: *mut BNBinaryView) {
395 ffi_wrap!("ObjectDestructor::destruct_view", {
396 let view_type = &*(ctxt as *mut Self);
397 let view = BinaryView { handle: view };
398 view_type.destruct_view(&view);
399 })
400 }
401
402 unsafe extern "C" fn cb_destruct_file_metadata(ctxt: *mut c_void, file: *mut BNFileMetadata) {
403 ffi_wrap!("ObjectDestructor::destruct_file_metadata", {
404 let view_type = &*(ctxt as *mut Self);
405 let file = FileMetadata::from_raw(file);
406 view_type.destruct_file_metadata(&file);
407 })
408 }
409
410 unsafe extern "C" fn cb_destruct_function(ctxt: *mut c_void, func: *mut BNFunction) {
411 ffi_wrap!("ObjectDestructor::destruct_function", {
412 let view_type = &*(ctxt as *mut Self);
413 let func = Function { handle: func };
414 view_type.destruct_function(&func);
415 })
416 }
417
418 unsafe fn as_callbacks(&'static mut self) -> BNObjectDestructionCallbacks {
419 BNObjectDestructionCallbacks {
420 context: std::mem::transmute(&self),
421 destructBinaryView: Some(Self::cb_destruct_binary_view),
422 destructFileMetadata: Some(Self::cb_destruct_file_metadata),
423 destructFunction: Some(Self::cb_destruct_function),
424 }
425 }
426
427 fn register(&'static mut self) {
428 unsafe { BNRegisterObjectDestructionCallbacks(&mut self.as_callbacks()) };
429 }
430
431 fn unregister(&'static mut self) {
432 unsafe { BNUnregisterObjectDestructionCallbacks(&mut self.as_callbacks()) };
433 }
434}
435
436pub fn version() -> String {
437 unsafe { BnString::into_string(BNGetVersionString()) }
438}
439
440pub fn build_id() -> u32 {
441 unsafe { BNGetBuildId() }
442}
443
444#[derive(Clone, PartialEq, Eq, Hash, Debug)]
445pub struct VersionInfo {
446 pub major: u32,
447 pub minor: u32,
448 pub build: u32,
449 pub channel: String,
450}
451
452impl VersionInfo {
453 pub(crate) fn from_raw(value: &BNVersionInfo) -> Self {
454 Self {
455 major: value.major,
456 minor: value.minor,
457 build: value.build,
458 channel: raw_to_string(value.channel).unwrap_or_default(),
460 }
461 }
462
463 pub(crate) fn from_owned_raw(value: BNVersionInfo) -> Self {
464 let owned = Self::from_raw(&value);
465 Self::free_raw(value);
466 owned
467 }
468
469 pub(crate) fn into_owned_raw(value: &Self) -> BNVersionInfo {
470 BNVersionInfo {
471 major: value.major,
472 minor: value.minor,
473 build: value.build,
474 channel: value.channel.as_ptr() as *mut c_char,
475 }
476 }
477
478 pub(crate) fn free_raw(value: BNVersionInfo) {
479 unsafe { BnString::free_raw(value.channel) };
480 }
481}
482
483impl TryFrom<&str> for VersionInfo {
484 type Error = ();
485
486 fn try_from(value: &str) -> Result<Self, Self::Error> {
487 let string = value.to_cstr();
488 let result = unsafe { BNParseVersionString(string.as_ptr()) };
489 if result.build == 0 && result.channel.is_null() && result.major == 0 && result.minor == 0 {
490 return Err(());
491 }
492 Ok(Self::from_owned_raw(result))
493 }
494}
495
496impl PartialOrd for VersionInfo {
497 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
498 Some(self.cmp(other))
499 }
500}
501
502impl Ord for VersionInfo {
503 fn cmp(&self, other: &Self) -> cmp::Ordering {
504 if self == other {
505 return cmp::Ordering::Equal;
506 }
507 let bn_version_0 = VersionInfo::into_owned_raw(self);
508 let bn_version_1 = VersionInfo::into_owned_raw(other);
509 if unsafe { BNVersionLessThan(bn_version_0, bn_version_1) } {
510 cmp::Ordering::Less
511 } else {
512 cmp::Ordering::Greater
513 }
514 }
515}
516
517pub fn version_info() -> VersionInfo {
518 let info_raw = unsafe { BNGetVersionInfo() };
519 VersionInfo::from_owned_raw(info_raw)
520}
521
522pub fn serial_number() -> String {
523 unsafe { BnString::into_string(BNGetSerialNumber()) }
524}
525
526pub fn is_license_validated() -> bool {
527 unsafe { BNIsLicenseValidated() }
528}
529
530pub fn licensed_user_email() -> String {
531 unsafe { BnString::into_string(BNGetLicensedUserEmail()) }
532}
533
534pub fn license_path() -> PathBuf {
535 user_directory().join("license.dat")
536}
537
538pub fn license_count() -> i32 {
539 unsafe { BNGetLicenseCount() }
540}
541
542#[cfg(not(feature = "demo"))]
548pub fn set_license(license: Option<&str>) {
549 let license = license.unwrap_or_default().to_cstr();
550 unsafe { BNSetLicense(license.as_ptr()) }
551}
552
553#[cfg(feature = "demo")]
554pub fn set_license(_license: Option<&str>) {}
555
556pub fn product() -> String {
557 unsafe { BnString::into_string(BNGetProduct()) }
558}
559
560pub fn product_type() -> String {
561 unsafe { BnString::into_string(BNGetProductType()) }
562}
563
564pub fn license_expiration_time() -> std::time::SystemTime {
565 let m = std::time::Duration::from_secs(unsafe { BNGetLicenseExpirationTime() });
566 std::time::UNIX_EPOCH + m
567}
568
569pub fn is_ui_enabled() -> bool {
570 unsafe { BNIsUIEnabled() }
571}
572
573pub fn is_database(file: &Path) -> bool {
574 let filename = file.to_cstr();
575 unsafe { BNIsDatabase(filename.as_ptr()) }
576}
577
578pub fn plugin_abi_version() -> u32 {
579 BN_CURRENT_CORE_ABI_VERSION
580}
581
582pub fn plugin_abi_minimum_version() -> u32 {
583 BN_MINIMUM_CORE_ABI_VERSION
584}
585
586pub fn core_abi_version() -> u32 {
587 unsafe { BNGetCurrentCoreABIVersion() }
588}
589
590pub fn core_abi_minimum_version() -> u32 {
591 unsafe { BNGetMinimumCoreABIVersion() }
592}
593
594pub fn plugin_ui_abi_version() -> u32 {
595 BN_CURRENT_UI_ABI_VERSION
596}
597
598pub fn plugin_ui_abi_minimum_version() -> u32 {
599 BN_MINIMUM_UI_ABI_VERSION
600}
601
602pub fn add_required_plugin_dependency(name: &str) {
603 let raw_name = name.to_cstr();
604 unsafe { BNAddRequiredPluginDependency(raw_name.as_ptr()) };
605}
606
607pub fn add_optional_plugin_dependency(name: &str) {
608 let raw_name = name.to_cstr();
609 unsafe { BNAddOptionalPluginDependency(raw_name.as_ptr()) };
610}
611
612#[cfg(not(feature = "no_exports"))]
614#[no_mangle]
615#[allow(non_snake_case)]
616pub extern "C" fn CorePluginABIVersion() -> u32 {
617 plugin_abi_version()
618}
619
620#[cfg(not(feature = "no_exports"))]
621#[no_mangle]
622pub extern "C" fn UIPluginABIVersion() -> u32 {
623 plugin_ui_abi_version()
624}