summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2021-05-03 18:45:19 -0400
committerKyleMiles <krm504@nyu.edu>2021-05-11 16:49:24 -0400
commiteb7a52bf4bd3b19c22f2eadda444ab045c674fe3 (patch)
tree2395d577d410908b5d0291682660dac2017c7e97 /rust/src
parent5731e612900bed0d542421e00e64324dbac9367e (diff)
Rust API : Better headless support; Introducing `binaryninja::open_view` and `binaryninja::open_view_with_options`, updated init/shutdown, script example, more setting support, and misc fixes
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/basicblock.rs2
-rw-r--r--rust/src/binaryview.rs43
-rw-r--r--rust/src/callingconvention.rs8
-rw-r--r--rust/src/command.rs40
-rw-r--r--rust/src/custombinaryview.rs40
-rw-r--r--rust/src/filemetadata.rs45
-rw-r--r--rust/src/function.rs12
-rw-r--r--rust/src/headless.rs32
-rw-r--r--rust/src/lib.rs278
-rw-r--r--rust/src/rc.rs9
-rw-r--r--rust/src/settings.rs80
11 files changed, 506 insertions, 83 deletions
diff --git a/rust/src/basicblock.rs b/rust/src/basicblock.rs
index 6b493803..3b9b7e5c 100644
--- a/rust/src/basicblock.rs
+++ b/rust/src/basicblock.rs
@@ -130,7 +130,7 @@ impl<C: BlockContext> BasicBlock<C> {
pub fn function(&self) -> Ref<Function> {
unsafe {
let func = BNGetBasicBlockFunction(self.handle);
- Ref::new(Function::from_raw(func))
+ Function::from_raw(func)
}
}
diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs
index aa5fb3f3..98d7c7b4 100644
--- a/rust/src/binaryview.rs
+++ b/rust/src/binaryview.rs
@@ -31,6 +31,7 @@ use crate::function::{Function, NativeBlock};
use crate::platform::Platform;
use crate::section::{Section, SectionBuilder};
use crate::segment::{Segment, SegmentBuilder};
+use crate::settings::Settings;
use crate::symbol::{Symbol, SymbolType};
use crate::types::{QualifiedName, Type};
use crate::Endianness;
@@ -138,7 +139,7 @@ pub trait BinaryViewExt: BinaryViewBase {
return Err(());
}
- unsafe { Ok(Ref::new(BinaryView { handle })) }
+ unsafe { Ok(BinaryView::from_raw(handle)) }
}
/// Reads up to `len` bytes from address `offset`
@@ -256,7 +257,7 @@ pub trait BinaryViewExt: BinaryViewBase {
}
}
- fn get_instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> {
+ fn instruction_len<A: Architecture>(&self, arch: &A, addr: u64) -> Option<usize> {
unsafe {
let size = BNGetInstructionLength(self.as_ref().handle, arch.as_ref().0, addr);
@@ -533,7 +534,7 @@ pub trait BinaryViewExt: BinaryViewBase {
return Err(());
}
- Ok(Ref::new(Function::from_raw(func)))
+ Ok(Function::from_raw(func))
}
}
@@ -565,7 +566,7 @@ pub trait BinaryViewExt: BinaryViewBase {
return Err(());
}
- Ok(Ref::new(Function::from_raw(handle)))
+ Ok(Function::from_raw(handle))
}
}
@@ -616,6 +617,34 @@ pub trait BinaryViewExt: BinaryViewBase {
);
}
}
+
+ fn load_settings<S: BnStrCompatible>(&self, view_type_name: S) -> Result<Ref<Settings>> {
+ let view_type_name = view_type_name.as_bytes_with_nul();
+ let settings_handle = unsafe {
+ BNBinaryViewGetLoadSettings(
+ self.as_ref().handle,
+ view_type_name.as_ref().as_ptr() as *mut _,
+ )
+ };
+
+ if settings_handle.is_null() {
+ Err(())
+ } else {
+ Ok(unsafe { Settings::from_raw(settings_handle) })
+ }
+ }
+
+ fn set_load_settings<S: BnStrCompatible>(&mut self, view_type_name: S, settings: &Settings) {
+ let view_type_name = view_type_name.as_bytes_with_nul();
+
+ unsafe {
+ BNBinaryViewSetLoadSettings(
+ self.as_ref().handle,
+ view_type_name.as_ref().as_ptr() as *mut _,
+ settings.handle,
+ )
+ };
+ }
}
impl<T: BinaryViewBase> BinaryViewExt for T {}
@@ -626,14 +655,14 @@ pub struct BinaryView {
}
impl BinaryView {
- pub(crate) unsafe fn from_raw(handle: *mut BNBinaryView) -> Self {
+ pub(crate) unsafe fn from_raw(handle: *mut BNBinaryView) -> Ref<Self> {
debug_assert!(!handle.is_null());
- Self { handle }
+ Ref::new(Self { handle })
}
pub fn from_filename<S: BnStrCompatible>(
- meta: &FileMetadata,
+ meta: &mut FileMetadata,
filename: S,
) -> Result<Ref<Self>> {
let file = filename.as_bytes_with_nul();
diff --git a/rust/src/callingconvention.rs b/rust/src/callingconvention.rs
index dcb88970..8cc1b71c 100644
--- a/rust/src/callingconvention.rs
+++ b/rust/src/callingconvention.rs
@@ -130,7 +130,7 @@ where
where
C: CallingConventionBase,
{
- ffi_wrap!("CallingConvention::callee_saved_registers", unsafe {
+ ffi_wrap!("CallingConvention::_callee_saved_registers", unsafe {
let ctxt = &*(ctxt as *mut CustomCallingConventionContext<C>);
let regs = ctxt.cc.callee_saved_registers();
@@ -559,7 +559,7 @@ unsafe impl<A: Architecture> RefCountable for CallingConvention<A> {
pub struct ConventionBuilder<A: Architecture> {
caller_saved_registers: Vec<A::Register>,
- callee_saved_registers: Vec<A::Register>,
+ _callee_saved_registers: Vec<A::Register>,
int_arg_registers: Vec<A::Register>,
float_arg_registers: Vec<A::Register>,
@@ -626,7 +626,7 @@ impl<A: Architecture> ConventionBuilder<A> {
pub fn new(arch: &A) -> Self {
Self {
caller_saved_registers: Vec::new(),
- callee_saved_registers: Vec::new(),
+ _callee_saved_registers: Vec::new(),
int_arg_registers: Vec::new(),
float_arg_registers: Vec::new(),
@@ -649,7 +649,7 @@ impl<A: Architecture> ConventionBuilder<A> {
}
reg_list!(caller_saved_registers);
- reg_list!(callee_saved_registers);
+ reg_list!(_callee_saved_registers);
reg_list!(int_arg_registers);
reg_list!(float_arg_registers);
diff --git a/rust/src/command.rs b/rust/src/command.rs
index 7dbc7436..3251e6b0 100644
--- a/rust/src/command.rs
+++ b/rust/src/command.rs
@@ -53,7 +53,9 @@ where
{
ffi_wrap!("Command::action", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.action(&view);
})
@@ -65,7 +67,9 @@ where
{
ffi_wrap!("Command::valid", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.valid(&view)
})
@@ -119,7 +123,9 @@ where
{
ffi_wrap!("AddressCommand::action", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.action(&view, addr);
})
@@ -131,7 +137,9 @@ where
{
ffi_wrap!("AddressCommand::valid", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.valid(&view, addr)
})
@@ -185,7 +193,9 @@ where
{
ffi_wrap!("RangeCommand::action", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.action(&view, addr..addr.wrapping_add(len));
})
@@ -202,7 +212,9 @@ where
{
ffi_wrap!("RangeCommand::valid", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
cmd.valid(&view, addr..addr.wrapping_add(len))
})
@@ -256,8 +268,12 @@ where
{
ffi_wrap!("FunctionCommand::action", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
- let func = Function::from_raw(func);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
+
+ debug_assert!(!func.is_null());
+ let func = Function { handle: func };
cmd.action(&view, &func);
})
@@ -273,8 +289,12 @@ where
{
ffi_wrap!("FunctionCommand::valid", unsafe {
let cmd = &*(ctxt as *const C);
- let view = BinaryView::from_raw(view);
- let func = Function::from_raw(func);
+
+ debug_assert!(!view.is_null());
+ let view = BinaryView { handle: view };
+
+ debug_assert!(!func.is_null());
+ let func = Function { handle: func };
cmd.valid(&view, &func)
})
diff --git a/rust/src/custombinaryview.rs b/rust/src/custombinaryview.rs
index 81272b0b..b1fda73a 100644
--- a/rust/src/custombinaryview.rs
+++ b/rust/src/custombinaryview.rs
@@ -96,7 +96,10 @@ where
let view_type = &*(ctxt as *mut T);
let data = BinaryView::from_raw(data);
- Ref::into_raw(view_type.load_settings_for_data(&data)).handle
+ match view_type.load_settings_for_data(&data) {
+ Ok(settings) => Ref::into_raw(settings).handle,
+ _ => ptr::null_mut() as *mut _,
+ }
})
}
@@ -138,11 +141,14 @@ where
pub trait BinaryViewTypeBase: AsRef<BinaryViewType> {
fn is_valid_for(&self, data: &BinaryView) -> bool;
- fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> {
- unsafe {
- Ref::new(Settings::from_raw(
- BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle),
- ))
+ fn load_settings_for_data(&self, data: &BinaryView) -> Result<Ref<Settings>> {
+ let settings_handle =
+ unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle) };
+
+ if settings_handle.is_null() {
+ Err(())
+ } else {
+ unsafe { Ok(Settings::from_raw(settings_handle)) }
}
}
}
@@ -181,7 +187,7 @@ pub trait BinaryViewTypeExt: BinaryViewTypeBase {
return Err(());
}
- unsafe { Ok(Ref::new(BinaryView::from_raw(handle))) }
+ unsafe { Ok(BinaryView::from_raw(handle)) }
}
}
@@ -227,12 +233,14 @@ impl BinaryViewTypeBase for BinaryViewType {
unsafe { BNIsBinaryViewTypeValidForData(self.0, data.handle) }
}
- fn load_settings_for_data(&self, data: &BinaryView) -> Ref<Settings> {
- unsafe {
- Ref::new(Settings::from_raw(BNGetBinaryViewLoadSettingsForData(
- self.0,
- data.handle,
- )))
+ fn load_settings_for_data(&self, data: &BinaryView) -> Result<Ref<Settings>> {
+ let settings_handle =
+ unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle) };
+
+ if settings_handle.is_null() {
+ Err(())
+ } else {
+ unsafe { Ok(Settings::from_raw(settings_handle)) }
}
}
}
@@ -280,7 +288,7 @@ pub struct CustomViewBuilder<'a, T: CustomBinaryViewType + ?Sized> {
pub unsafe trait CustomBinaryView: 'static + BinaryViewBase + Sync + Sized {
type Args: Send;
- fn new(handle: BinaryView, args: &Self::Args) -> Result<Self>;
+ fn new(handle: &BinaryView, args: &Self::Args) -> Result<Self>;
fn init(&self, args: Self::Args) -> Result<()>;
}
@@ -377,7 +385,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
let context = &mut *(ctxt as *mut CustomViewContext<V>);
let handle = BinaryView::from_raw(context.raw_handle);
- if let Ok(v) = V::new(handle, &context.args) {
+ if let Ok(v) = V::new(handle.as_ref(), &context.args) {
ptr::write(&mut context.view, v);
context.initialized = true;
@@ -730,7 +738,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
(*ctxt).raw_handle = res;
Ok(CustomView {
- handle: Ref::new(BinaryView::from_raw(res)),
+ handle: BinaryView::from_raw(res),
_builder: PhantomData,
})
}
diff --git a/rust/src/filemetadata.rs b/rust/src/filemetadata.rs
index fa7d65e1..809abea4 100644
--- a/rust/src/filemetadata.rs
+++ b/rust/src/filemetadata.rs
@@ -31,6 +31,8 @@ use binaryninjacore_sys::{
BNMarkFileSaved,
BNNavigate,
BNNewFileReference,
+ BNOpenDatabaseForConfiguration,
+ BNOpenExistingDatabase,
BNRedo,
BNSetFilename,
BNUndo,
@@ -168,10 +170,49 @@ impl FileMetadata {
if res.is_null() {
Err(())
} else {
- Ok(Ref::new(BinaryView::from_raw(res)))
+ Ok(BinaryView::from_raw(res))
}
}
}
+
+ pub fn open_database_for_configuration<S: BnStrCompatible>(
+ &mut self,
+ filename: S,
+ ) -> Result<Ref<BinaryView>, ()> {
+ let filename = filename.as_bytes_with_nul();
+ unsafe {
+ let bv =
+ BNOpenDatabaseForConfiguration(self.handle, filename.as_ref().as_ptr() as *const _);
+
+ if bv.is_null() {
+ Err(())
+ } else {
+ Ok(BinaryView::from_raw(bv))
+ }
+ }
+ }
+
+ pub fn open_database<S: BnStrCompatible>(
+ &mut self,
+ filename: S,
+ ) -> Result<Ref<BinaryView>, ()> {
+ let filename = filename.as_bytes_with_nul();
+ let filename_ptr = filename.as_ref().as_ptr() as *mut _;
+
+ let view = unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) };
+
+ // TODO : add optional progress function
+ // let view = match progress_func {
+ // None => BNOpenExistingDatabase(self.handle, filename_ptr),
+ // _ => BNOpenExistingDatabaseWithProgress(self.handle, str(filename), None, ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, cur, total: progress_func(cur, total)))
+ // };
+
+ if view.is_null() {
+ Err(())
+ } else {
+ Ok(unsafe { BinaryView::from_raw(view) })
+ }
+ }
}
impl ToOwned for FileMetadata {
@@ -197,6 +238,4 @@ unsafe impl RefCountable for FileMetadata {
/*
BNCreateDatabase,
BNCreateDatabaseWithProgress,
-BNOpenExistingDatabase,
-BNOpenExistingDatabaseWithProgress,
*/
diff --git a/rust/src/function.rs b/rust/src/function.rs
index 41c3a973..4230900f 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -68,7 +68,7 @@ impl Iterator for NativeBlockIter {
None
} else {
self.bv
- .get_instruction_len(&self.arch, res)
+ .instruction_len(&self.arch, res)
.map(|x| {
self.cur += x as u64;
res
@@ -112,15 +112,15 @@ impl BlockContext for NativeBlock {
#[derive(PartialEq, Eq, Hash)]
pub struct Function {
- handle: *mut BNFunction,
+ pub(crate) handle: *mut BNFunction,
}
unsafe impl Send for Function {}
unsafe impl Sync for Function {}
impl Function {
- pub(crate) unsafe fn from_raw(handle: *mut BNFunction) -> Self {
- Self { handle }
+ pub(crate) unsafe fn from_raw(handle: *mut BNFunction) -> Ref<Self> {
+ Ref::new(Self { handle })
}
pub fn arch(&self) -> CoreArchitecture {
@@ -140,7 +140,7 @@ impl Function {
pub fn view(&self) -> Ref<BinaryView> {
unsafe {
let view = BNGetFunctionData(self.handle);
- Ref::new(BinaryView::from_raw(view))
+ BinaryView::from_raw(view)
}
}
@@ -282,6 +282,6 @@ unsafe impl<'a> CoreOwnedArrayWrapper<'a> for Function {
type Wrapped = Guard<'a, Function>;
unsafe fn wrap_raw(raw: &'a *mut BNFunction, context: &'a ()) -> Guard<'a, Function> {
- Guard::new(Function::from_raw(*raw), context)
+ Guard::new(Function { handle: *raw }, context)
}
}
diff --git a/rust/src/headless.rs b/rust/src/headless.rs
index f7b9f16d..39711f94 100644
--- a/rust/src/headless.rs
+++ b/rust/src/headless.rs
@@ -63,9 +63,7 @@ fn binja_path() -> PathBuf {
PathBuf::from(env::var("PROGRAMFILES").unwrap()).join("Vector35\\BinaryNinja\\")
}
-use binaryninjacore_sys::{
- BNInitCorePlugins, BNInitRepoPlugins, BNInitUserPlugins, BNSetBundledPluginDirectory,
-};
+use binaryninjacore_sys::{BNInitPlugins, BNInitRepoPlugins, BNSetBundledPluginDirectory};
pub fn init() {
unsafe {
@@ -73,8 +71,32 @@ pub fn init() {
let path = CString::new(path.into_string().unwrap()).unwrap();
BNSetBundledPluginDirectory(path.as_ptr());
- BNInitCorePlugins();
- BNInitUserPlugins();
+ BNInitPlugins(true);
BNInitRepoPlugins();
}
}
+
+pub fn shutdown() {
+ //! Unloads plugins, stops all worker threads, and closes open logs
+ //! Important! : Must be called at the end of scripts
+
+ unsafe { binaryninjacore_sys::BNShutdown() };
+}
+
+pub fn script_helper(func: fn()) {
+ //! Prelued-postlued helper function:
+ //! ```
+ //! fn main() {
+ //! binaryninja::headless::script_helper(|| {
+ //! binaryninja::open_view("/bin/cat")
+ //! .expect("Couldn't open `/bin/cat`")
+ //! .iter()
+ //! .for_each(|func| println!(" `{}`", func.symbol().full_name()));
+ //! });
+ //! }
+ //! ```
+
+ init();
+ func();
+ shutdown();
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 94e6b966..b8919fb1 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -17,9 +17,7 @@
#[macro_use]
extern crate log;
-pub extern crate binaryninjacore_sys; // For testing functions and stuff
-#[cfg(feature = "ui")]
-pub extern crate binaryninjaui_sys; // For testing functions and stuff
+pub extern crate binaryninjacore_sys;
extern crate libc;
#[cfg(feature = "rayon")]
extern crate rayon;
@@ -62,6 +60,11 @@ pub mod string;
pub mod symbol;
pub mod types;
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+
pub use binaryninjacore_sys::BNBranchType as BranchType;
pub use binaryninjacore_sys::BNEndianness as Endianness;
@@ -213,6 +216,251 @@ pub mod logger {
}
}
+pub fn open_view<F: AsRef<Path>>(filename: F) -> Result<rc::Ref<binaryview::BinaryView>, String> {
+ use crate::binaryview::BinaryViewExt;
+ use crate::custombinaryview::BinaryViewTypeExt;
+
+ let filename = filename.as_ref();
+
+ let mut metadata = filemetadata::FileMetadata::with_filename(filename.to_str().unwrap());
+
+ let mut is_bndb = false;
+ let view = match match filename.ends_with(".bndb") {
+ true => {
+ match File::open(filename) {
+ Ok(mut file) => {
+ let mut buf = [0; 15];
+ match file.read_exact(&mut buf) {
+ Ok(_) => {
+ let sqlite_string = "SQLite format 3";
+ if buf != sqlite_string.as_bytes() {
+ return Err("Not a valid BNDB (invalid magic)".to_string());
+ }
+ }
+ _ => return Err("Not a valid BNDB (too small)".to_string()),
+ }
+ }
+ _ => return Err("Could not open file".to_string()),
+ }
+ is_bndb = true;
+ metadata.open_database(filename.to_str().unwrap())
+ }
+ false => binaryview::BinaryView::from_filename(&mut metadata, filename.to_str().unwrap()),
+ } {
+ Ok(view) => view,
+ _ => return Err("Unable to open file".to_string()),
+ };
+
+ let mut bv = None;
+ for available_view in custombinaryview::BinaryViewType::list_valid_types_for(&view).iter() {
+ // TODO : These weird comparison arguments is probably symptomatic of something we should fix (fix other instance too)
+ if bv.is_none() && **available_view.name() != *"Raw" {
+ if is_bndb {
+ bv = Some(
+ view.metadata()
+ .get_view_of_type(available_view.name())
+ .unwrap(),
+ );
+ } else {
+ // TODO : add log prints
+ // println!("Opening view of type: `{}`", available_view.name());
+ bv = Some(available_view.open(&view).unwrap());
+ }
+ break;
+ }
+ }
+
+ let bv = match bv {
+ None => {
+ if is_bndb {
+ match view.metadata().get_view_of_type("Raw") {
+ Ok(view) => view,
+ _ => return Err("Could not get raw view from bndb".to_string()),
+ }
+ } else {
+ match custombinaryview::BinaryViewType::by_name("Raw")
+ .unwrap()
+ .open(&view)
+ {
+ Ok(view) => view,
+ _ => return Err("Could not open raw view".to_string()),
+ }
+ }
+ }
+ Some(bv) => bv,
+ };
+
+ bv.update_analysis_and_wait();
+ Ok(bv)
+}
+
+pub fn open_view_with_options<F: AsRef<Path>>(
+ filename: F,
+ update_analysis_and_wait: bool,
+ options: Option<HashMap<&str, &str>>,
+) -> Result<rc::Ref<binaryview::BinaryView>, String> {
+ //! This is incomplete, but should work in most cases:
+ //! ```
+ //! let settings = [("analysis.linearSweep.autorun", "false")]
+ //! .iter()
+ //! .cloned()
+ //! .collect();
+ //!
+ //! let bv = binaryninja::open_view_with_options("/bin/cat", true, Some(settings))
+ //! .expect("Couldn't open `/bin/cat`");
+ //! ```
+
+ use crate::binaryview::BinaryViewExt;
+ use crate::custombinaryview::{BinaryViewTypeBase, BinaryViewTypeExt};
+
+ let filename = filename.as_ref();
+
+ let mut metadata = filemetadata::FileMetadata::with_filename(filename.to_str().unwrap());
+
+ let mut is_bndb = false;
+ let mut view = match match filename.ends_with(".bndb") {
+ true => {
+ match File::open(filename) {
+ Ok(mut file) => {
+ let mut buf = [0; 15];
+ match file.read_exact(&mut buf) {
+ Ok(_) => {
+ let sqlite_string = "SQLite format 3";
+ if buf != sqlite_string.as_bytes() {
+ return Err("Not a valid BNDB (invalid magic)".to_string());
+ }
+ }
+ _ => return Err("Not a valid BNDB (too small)".to_string()),
+ }
+ }
+ _ => return Err("Could not open file".to_string()),
+ }
+ is_bndb = true;
+ metadata.open_database_for_configuration(filename.to_str().unwrap())
+ }
+ false => binaryview::BinaryView::from_filename(&mut metadata, filename.to_str().unwrap()),
+ } {
+ Ok(view) => view,
+ _ => return Err("Unable to open file".to_string()),
+ };
+
+ let mut universal_view_type = None;
+ let mut view_type = None;
+ for available_view in custombinaryview::BinaryViewType::list_valid_types_for(&view).iter() {
+ if available_view.name().as_ref() == "Universal".as_bytes() {
+ universal_view_type = Some(available_view);
+ } else if view_type.is_none() && **available_view.name() != *"Raw" {
+ view_type = Some(available_view);
+ }
+ }
+
+ let view_type = match view_type {
+ None => custombinaryview::BinaryViewType::by_name("Mapped").unwrap(),
+ Some(view_type) => view_type,
+ };
+
+ // I have no idea why this is needed
+ let setting_id = format!("{}{}", view_type.name(), "_settings");
+ let mut default_settings = settings::Settings::new(setting_id);
+ default_settings.deserialize_schema(settings::Settings::new("").serialize_schema());
+ default_settings.set_resource_id(view_type.name());
+
+ let mut load_settings = match (is_bndb, view.load_settings(view_type.name())) {
+ (true, Ok(settings)) => Some(settings),
+ _ => None,
+ };
+
+ if load_settings.is_none() {
+ // TODO : The Python version has a "fixme" here but I have no idea why
+ if universal_view_type.is_some()
+ && options.is_some()
+ && options
+ .as_ref()
+ .unwrap()
+ .contains_key("files.universal.architecturePreference")
+ {
+ load_settings = match universal_view_type
+ .unwrap()
+ .load_settings_for_data(view.as_ref())
+ {
+ Ok(settings) => Some(settings),
+ _ => return Err("Could not load settings for universal view data".to_string()),
+ }
+
+ // TODO : finish converting this to Rust
+ // arch_list = json.loads(load_settings.get_string('loader.universal.architectures'))
+ // arch_entry = [entry for entry in arch_list if entry['architecture'] == options['files.universal.architecturePreference'][0]]
+ // if not arch_entry:
+ // log.log_error(f"Could not load {options['files.universal.architecturePreference'][0]} from Universal image. Entry not found!")
+ // return None
+
+ // let tmp_load_settings = settings::Settings::new(BNGetUniqueIdentifierString());
+ // tmp_load_settings.deserialize_schema(arch_entry[0]['loadSchema']);
+ // load_settings = Some(tmp_load_settings);
+ } else {
+ load_settings = match view_type.load_settings_for_data(view.as_ref()) {
+ Ok(settings) => Some(settings),
+ _ => None,
+ }
+ }
+ }
+ if load_settings.is_none() {
+ // log.log_error(f"Could not get load settings for binary view of type `{bvt.name}`")
+ return Ok(view);
+ }
+ let mut load_settings = load_settings.unwrap();
+ load_settings.set_resource_id(view_type.name());
+ view.set_load_settings(view_type.name(), load_settings.as_ref());
+
+ match options {
+ Some(options) => {
+ for (setting, value) in options {
+ if load_settings.contains(setting) {
+ if !load_settings.set_json(setting, value, Some(view.as_ref()), None) {
+ return Err(format!("Setting: {} set operation failed!", setting));
+ }
+ } else if default_settings.contains(setting) {
+ if !default_settings.set_json(setting, value, Some(view.as_ref()), None) {
+ return Err(format!("Setting: {} set operation failed!", setting));
+ }
+ } else {
+ return Err(format!("Setting: {} not available!", setting));
+ }
+ }
+ }
+ None => (),
+ }
+
+ if is_bndb {
+ let view = view
+ .metadata()
+ .open_database(filename.to_str().unwrap())
+ .expect("Couldn't open database");
+ let view_type_name = view_type.name();
+ // TODO : handle the case where the view doesn't exist in the bndb
+ let bv = unsafe {
+ binaryview::BinaryView::from_raw(binaryninjacore_sys::BNGetFileViewOfType(
+ view.metadata().handle,
+ view_type_name.as_ref().as_ptr() as *mut _,
+ ))
+ };
+ if update_analysis_and_wait {
+ bv.update_analysis_and_wait();
+ }
+ Ok(bv)
+ } else {
+ match view_type.open(&view) {
+ Ok(bv) => {
+ if update_analysis_and_wait {
+ bv.update_analysis_and_wait();
+ }
+ Ok(bv)
+ }
+ _ => Ok(view),
+ }
+ }
+}
+
pub fn version() -> string::BnString {
unsafe { string::BnString::from_raw(binaryninjacore_sys::BNGetVersionString()) }
}
@@ -225,18 +473,6 @@ pub fn plugin_abi_minimum_version() -> u32 {
binaryninjacore_sys::BN_MINIMUM_CORE_ABI_VERSION
}
-// TODO : We need to get this from uitypes.h::BN_CURRENT_UI_ABI_VERSION
-pub fn plugin_ui_abi_version() -> u32 {
- //xxxx::BN_CURRENT_UI_ABI_VERSION
- 2
-}
-
-// TODO : We need to get this from uitypes.h::BN_MINIMUM_UI_ABI_VERSION
-pub fn plugin_ui_abi_minimum_version() -> u32 {
- //xxxx::BN_MINIMUM_UI_ABI_VERSION
- 2
-}
-
pub fn core_abi_version() -> u32 {
unsafe { binaryninjacore_sys::BNGetCurrentCoreABIVersion() }
}
@@ -245,21 +481,21 @@ pub fn core_abi_minimum_version() -> u32 {
unsafe { binaryninjacore_sys::BNGetMinimumCoreABIVersion() }
}
-// TODO : We need to get this from uitypes.h::UIPluginABIVersion()
-pub fn ui_plugin_abi_version() -> u32 {
- //unsafe { xxxx::UIPluginABIVersion() }
- 2
+pub fn plugin_ui_abi_version() -> u32 {
+ binaryninjacore_sys::BN_CURRENT_UI_ABI_VERSION
+}
+
+pub fn plugin_ui_abi_minimum_version() -> u32 {
+ binaryninjacore_sys::BN_MINIMUM_UI_ABI_VERSION
}
// Provide ABI version automatically so that the core can verify binary compatibility
-#[cfg(any(windows, not(feature = "headless")))]
#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CorePluginABIVersion() -> u32 {
plugin_abi_version()
}
-#[cfg(any(windows, not(feature = "headless")))]
#[no_mangle]
pub extern "C" fn UIPluginABIVersion() -> u32 {
plugin_ui_abi_version()
diff --git a/rust/src/rc.rs b/rust/src/rc.rs
index 9264e3bd..7c5d610f 100644
--- a/rust/src/rc.rs
+++ b/rust/src/rc.rs
@@ -163,10 +163,7 @@ where
unsafe fn wrap_raw(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped;
}
-pub struct Array<P>
-where
- P: CoreOwnedArrayProvider,
-{
+pub struct Array<P: CoreOwnedArrayProvider> {
contents: *mut P::Raw,
count: usize,
context: P::Context,
@@ -189,8 +186,8 @@ impl<P: CoreOwnedArrayProvider> Array<P> {
pub(crate) unsafe fn new(raw: *mut P::Raw, count: usize, context: P::Context) -> Self {
Self {
contents: raw,
- count: count,
- context: context,
+ count,
+ context,
}
}
diff --git a/rust/src/settings.rs b/rust/src/settings.rs
index 09fa14a6..a555cb4c 100644
--- a/rust/src/settings.rs
+++ b/rust/src/settings.rs
@@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use binaryninjacore_sys::*;
-
pub use binaryninjacore_sys::BNSettingsScope as SettingsScope;
+use binaryninjacore_sys::*;
+use crate::binaryview::BinaryView;
use crate::rc::*;
+use crate::string::{BnStrCompatible, BnString};
+
+use std::ptr;
#[derive(PartialEq, Eq, Hash)]
pub struct Settings {
@@ -27,10 +30,79 @@ unsafe impl Send for Settings {}
unsafe impl Sync for Settings {}
impl Settings {
- pub(crate) unsafe fn from_raw(handle: *mut BNSettings) -> Self {
+ pub(crate) unsafe fn from_raw(handle: *mut BNSettings) -> Ref<Self> {
debug_assert!(!handle.is_null());
- Self { handle }
+ Ref::new(Self { handle })
+ }
+
+ pub fn new<S: BnStrCompatible>(instance_id: S) -> Ref<Self> {
+ let instance_id = instance_id.as_bytes_with_nul();
+ unsafe {
+ let handle = BNCreateSettings(instance_id.as_ref().as_ptr() as *mut _);
+
+ debug_assert!(!handle.is_null());
+
+ Ref::new(Self { handle })
+ }
+ }
+
+ pub fn set_resource_id<S: BnStrCompatible>(&mut self, resource_id: S) {
+ let resource_id = resource_id.as_bytes_with_nul();
+ unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ref().as_ptr() as *mut _) };
+ }
+
+ pub fn serialize_schema(&self) -> BnString {
+ unsafe { BnString::from_raw(BNSettingsSerializeSchema(self.handle)) }
+ }
+
+ pub fn deserialize_schema<S: BnStrCompatible>(&self, schema: S) -> bool {
+ let schema = schema.as_bytes_with_nul();
+ unsafe {
+ BNSettingsDeserializeSchema(
+ self.handle,
+ schema.as_ref().as_ptr() as *mut _,
+ BNSettingsScope::SettingsAutoScope,
+ true,
+ )
+ }
+ }
+
+ pub fn contains<S: BnStrCompatible>(&self, key: S) -> bool {
+ let key = key.as_bytes_with_nul();
+
+ unsafe { BNSettingsContains(self.handle, key.as_ref().as_ptr() as *mut _) }
+ }
+
+ pub fn set_json<S1: BnStrCompatible, S2: BnStrCompatible>(
+ &mut self,
+ key: S1,
+ value: S2,
+ view: Option<&BinaryView>,
+ scope: Option<SettingsScope>,
+ ) -> bool {
+ let key = key.as_bytes_with_nul();
+ let value = value.as_bytes_with_nul();
+
+ let view_handle = match view {
+ Some(view) => view.handle,
+ None => ptr::null_mut() as *mut _,
+ };
+
+ let scope = match scope {
+ Some(scope) => scope,
+ None => SettingsScope::SettingsAutoScope,
+ };
+
+ unsafe {
+ BNSettingsSetJson(
+ self.handle,
+ view_handle,
+ scope,
+ key.as_ref().as_ptr() as *mut _,
+ value.as_ref().as_ptr() as *mut _,
+ )
+ }
}
}