summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2024-08-21 10:30:46 -0400
committerJosh Ferrell <josh@vector35.com>2024-08-21 10:30:46 -0400
commit7a0ab6ffa99533bc241c88b8761fb82d795dc832 (patch)
tree32d3cc8339f681f9a1755fb36a2c69580af42042
parent3d088d6dae28ab851b584a11678c9993eb18da10 (diff)
Add progress context to load APIs
-rw-r--r--binaryninjacore.h10
-rw-r--r--binaryview.cpp8
-rw-r--r--python/binaryview.py14
-rw-r--r--rust/src/lib.rs180
-rw-r--r--rust/src/update.rs14
5 files changed, 197 insertions, 29 deletions
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 8b33af27..05f77741 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -37,14 +37,14 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
-#define BN_CURRENT_CORE_ABI_VERSION 74
+#define BN_CURRENT_CORE_ABI_VERSION 75
// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
// will require rebuilding. The minimum version is increased when there are
// incompatible changes that break binary compatibility, such as changes to
// existing types or functions.
-#define BN_MINIMUM_CORE_ABI_VERSION 74
+#define BN_MINIMUM_CORE_ABI_VERSION 75
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -6180,9 +6180,9 @@ extern "C"
BINARYNINJACOREAPI bool BNCheckForStringAnnotationType(BNBinaryView* view, uint64_t addr, char** value, BNStringType* strType,
bool allowShortStrings, bool allowLargeStrings, size_t childWidth);
- BINARYNINJACOREAPI BNBinaryView* BNLoadFilename(const char* const filename, const bool updateAnalysis, const char* options, bool (*progress)(size_t, size_t));
- BINARYNINJACOREAPI BNBinaryView* BNLoadProjectFile(BNProjectFile* projectFile, const bool updateAnalysis, const char* options, bool (*progress)(size_t, size_t));
- BINARYNINJACOREAPI BNBinaryView* BNLoadBinaryView(BNBinaryView* view, const bool updateAnalysis, const char* options, bool (*progress)(size_t, size_t));
+ BINARYNINJACOREAPI BNBinaryView* BNLoadFilename(const char* const filename, const bool updateAnalysis, const char* options, BNProgressFunction progress, void* progressContext);
+ BINARYNINJACOREAPI BNBinaryView* BNLoadProjectFile(BNProjectFile* projectFile, const bool updateAnalysis, const char* options, BNProgressFunction progress, void* progressContext);
+ BINARYNINJACOREAPI BNBinaryView* BNLoadBinaryView(BNBinaryView* view, const bool updateAnalysis, const char* options, BNProgressFunction progress, void* progressContext);
BINARYNINJACOREAPI BNExternalLibrary* BNBinaryViewAddExternalLibrary(BNBinaryView* view, const char* name, BNProjectFile* backingFile, bool isAuto);
BINARYNINJACOREAPI void BNBinaryViewRemoveExternalLibrary(BNBinaryView* view, const char* name);
diff --git a/binaryview.cpp b/binaryview.cpp
index 2f24904d..9c1373c1 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -5427,7 +5427,9 @@ Ref<BinaryView> BinaryNinja::Load(Ref<BinaryView> view, bool updateAnalysis,
Ref<BinaryView> BinaryNinja::Load(const std::string& filename, bool updateAnalysis, const std::string& options, std::function<bool(size_t, size_t)> progress)
{
- BNBinaryView* handle = BNLoadFilename(filename.c_str(), updateAnalysis, options.c_str(), (bool (*)(size_t, size_t))progress.target<bool (*)(size_t, size_t)>());
+ ProgressContext cb;
+ cb.callback = progress;
+ BNBinaryView* handle = BNLoadFilename(filename.c_str(), updateAnalysis, options.c_str(), ProgressCallback, &cb);
if (!handle)
return nullptr;
return new BinaryView(handle);
@@ -5444,7 +5446,9 @@ Ref<BinaryView> BinaryNinja::Load(const DataBuffer& rawData, bool updateAnalysis
Ref<BinaryView> BinaryNinja::Load(Ref<BinaryView> view, bool updateAnalysis, const std::string& options, std::function<bool(size_t, size_t)> progress)
{
- BNBinaryView* handle = BNLoadBinaryView(view->GetObject(), updateAnalysis, options.c_str(), (bool (*)(size_t, size_t))progress.target<bool (*)(size_t, size_t)>());
+ ProgressContext cb;
+ cb.callback = progress;
+ BNBinaryView* handle = BNLoadBinaryView(view->GetObject(), updateAnalysis, options.c_str(), ProgressCallback, &cb);
if (!handle)
return nullptr;
return new BinaryView(handle);
diff --git a/python/binaryview.py b/python/binaryview.py
index 960476d6..484e704f 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -2646,7 +2646,7 @@ class BinaryView:
return BinaryView(file_metadata=file_metadata, handle=view)
@staticmethod
- def load(source: Union[str, bytes, bytearray, 'databuffer.DataBuffer', 'os.PathLike', 'BinaryView', 'project.ProjectFile'], update_analysis: Optional[bool] = True,
+ def load(source: Union[str, bytes, bytearray, 'databuffer.DataBuffer', 'os.PathLike', 'BinaryView', 'project.ProjectFile'], update_analysis: bool = True,
progress_func: Optional[ProgressFuncType] = None, options: Mapping[str, Any] = {}) -> Optional['BinaryView']:
"""
``load`` opens, generates default load options (which are overridable), and returns the first available \
@@ -2687,21 +2687,21 @@ class BinaryView:
binaryninja._init_plugins()
if progress_func is None:
- progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda cur, total: True)
+ progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, cur, total: True)
else:
- progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda cur, total: progress_func(cur, total))
+ progress_cfunc = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(lambda ctxt, cur, total: progress_func(cur, total))
if isinstance(source, os.PathLike):
source = str(source)
if isinstance(source, BinaryView):
- handle = core.BNLoadBinaryView(source.handle, update_analysis, json.dumps(options), progress_cfunc)
+ handle = core.BNLoadBinaryView(source.handle, update_analysis, json.dumps(options), progress_cfunc, None)
elif isinstance(source, project.ProjectFile):
- handle = core.BNLoadProjectFile(source._handle, update_analysis, json.dumps(options), progress_cfunc)
+ handle = core.BNLoadProjectFile(source._handle, update_analysis, json.dumps(options), progress_cfunc, None)
elif isinstance(source, str):
- handle = core.BNLoadFilename(source, update_analysis, json.dumps(options), progress_cfunc)
+ handle = core.BNLoadFilename(source, update_analysis, json.dumps(options), progress_cfunc, None)
elif isinstance(source, bytes) or isinstance(source, bytearray) or isinstance(source, databuffer.DataBuffer):
raw_view = BinaryView.new(source)
- handle = core.BNLoadBinaryView(raw_view.handle, update_analysis, json.dumps(options), progress_cfunc)
+ handle = core.BNLoadBinaryView(raw_view.handle, update_analysis, json.dumps(options), progress_cfunc, None)
else:
raise NotImplementedError
return BinaryView(handle=handle) if handle else None
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index bd46611d..d881c943 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -173,6 +173,7 @@ pub mod types;
pub mod update;
use std::path::PathBuf;
+use std::ptr;
pub use binaryninjacore_sys::BNBranchType as BranchType;
pub use binaryninjacore_sys::BNEndianness as Endianness;
@@ -202,17 +203,76 @@ use string::IntoJson;
const BN_FULL_CONFIDENCE: u8 = 255;
const BN_INVALID_EXPR: usize = usize::MAX;
+unsafe extern "C" fn cb_progress_func<F: FnMut(usize, usize) -> bool>(
+ ctxt: *mut std::ffi::c_void,
+ progress: usize,
+ total: usize,
+) -> bool {
+ if ctxt.is_null() {
+ return true;
+ }
+ let closure: &mut F = std::mem::transmute(ctxt);
+ closure(progress, total)
+}
+
+
+unsafe extern "C" fn cb_progress_nop(
+ _ctxt: *mut std::ffi::c_void,
+ _arg1: usize,
+ _arg2: usize
+) -> bool {
+ true
+}
+
+
/// The main way to open and load files into Binary Ninja. Make sure you've properly initialized the core before calling this function. See [`crate::headless::init()`]
-pub fn load<S: BnStrCompatible>(filename: S) -> Option<rc::Ref<binaryview::BinaryView>> {
+pub fn load<S>(
+ filename: S,
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ S: BnStrCompatible,
+{
+ let filename = filename.into_bytes_with_nul();
+ let options = "\x00";
+
+
+ let handle = unsafe {
+ binaryninjacore_sys::BNLoadFilename(
+ filename.as_ref().as_ptr() as *mut _,
+ true,
+ options.as_ptr() as *mut core::ffi::c_char,
+ Some(cb_progress_nop),
+ ptr::null_mut(),
+ )
+ };
+
+ if handle.is_null() {
+ None
+ } else {
+ Some(unsafe { BinaryView::from_raw(handle) })
+ }
+}
+
+pub fn load_with_progress<S, F>(
+ filename: S,
+ mut progress: F,
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ S: BnStrCompatible,
+ F: FnMut(usize, usize) -> bool,
+{
let filename = filename.into_bytes_with_nul();
let options = "\x00";
+ let progress_ctx = &mut progress as *mut F as *mut std::ffi::c_void;
+
let handle = unsafe {
binaryninjacore_sys::BNLoadFilename(
filename.as_ref().as_ptr() as *mut _,
true,
options.as_ptr() as *mut core::ffi::c_char,
- None,
+ Some(cb_progress_func::<F>),
+ progress_ctx,
)
};
@@ -240,11 +300,15 @@ pub fn load<S: BnStrCompatible>(filename: S) -> Option<rc::Ref<binaryview::Binar
/// let bv = binaryninja::load_with_options("/bin/cat", true, Some(json!("analysis.linearSweep.autorun": false).to_string()))
/// .expect("Couldn't open `/bin/cat`");
/// ```
-pub fn load_with_options<S: BnStrCompatible, O: IntoJson>(
+pub fn load_with_options<S, O>(
filename: S,
update_analysis_and_wait: bool,
options: Option<O>,
-) -> Option<rc::Ref<binaryview::BinaryView>> {
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ S: BnStrCompatible,
+ O: IntoJson,
+{
let filename = filename.into_bytes_with_nul();
let options_or_default = if let Some(opt) = options {
@@ -266,7 +330,8 @@ pub fn load_with_options<S: BnStrCompatible, O: IntoJson>(
filename.as_ref().as_ptr() as *mut _,
update_analysis_and_wait,
options_or_default.as_ptr() as *mut core::ffi::c_char,
- None,
+ Some(cb_progress_nop),
+ core::ptr::null_mut(),
)
};
@@ -277,11 +342,63 @@ pub fn load_with_options<S: BnStrCompatible, O: IntoJson>(
}
}
-pub fn load_view<O: IntoJson>(
+pub fn load_with_options_and_progress<S, O, F>(
+ filename: S,
+ update_analysis_and_wait: bool,
+ options: Option<O>,
+ progress: Option<F>,
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ S: BnStrCompatible,
+ O: IntoJson,
+ F: FnMut(usize, usize) -> bool,
+{
+ let filename = filename.into_bytes_with_nul();
+
+ let options_or_default = if let Some(opt) = options {
+ opt.get_json_string()
+ .ok()?
+ .into_bytes_with_nul()
+ .as_ref()
+ .to_vec()
+ } else {
+ Metadata::new_of_type(MetadataType::KeyValueDataType)
+ .get_json_string()
+ .ok()?
+ .as_ref()
+ .to_vec()
+ };
+
+ let progress_ctx = match progress {
+ Some(mut x) => &mut x as *mut F as *mut std::ffi::c_void,
+ None => core::ptr::null_mut()
+ };
+
+ let handle = unsafe {
+ binaryninjacore_sys::BNLoadFilename(
+ filename.as_ref().as_ptr() as *mut _,
+ update_analysis_and_wait,
+ options_or_default.as_ptr() as *mut core::ffi::c_char,
+ Some(cb_progress_func::<F>),
+ progress_ctx,
+ )
+ };
+
+ if handle.is_null() {
+ None
+ } else {
+ Some(unsafe { BinaryView::from_raw(handle) })
+ }
+}
+
+pub fn load_view<O>(
bv: &BinaryView,
update_analysis_and_wait: bool,
options: Option<O>,
-) -> Option<rc::Ref<binaryview::BinaryView>> {
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ O: IntoJson,
+{
let options_or_default = if let Some(opt) = options {
opt.get_json_string()
.ok()?
@@ -301,7 +418,54 @@ pub fn load_view<O: IntoJson>(
bv.handle as *mut _,
update_analysis_and_wait,
options_or_default.as_ptr() as *mut core::ffi::c_char,
- None,
+ Some(cb_progress_nop),
+ core::ptr::null_mut(),
+ )
+ };
+
+ if handle.is_null() {
+ None
+ } else {
+ Some(unsafe { BinaryView::from_raw(handle) })
+ }
+}
+
+pub fn load_view_with_progress<O, F>(
+ bv: &BinaryView,
+ update_analysis_and_wait: bool,
+ options: Option<O>,
+ progress: Option<F>,
+) -> Option<rc::Ref<binaryview::BinaryView>>
+where
+ O: IntoJson,
+ F: FnMut(usize, usize) -> bool,
+{
+ let options_or_default = if let Some(opt) = options {
+ opt.get_json_string()
+ .ok()?
+ .into_bytes_with_nul()
+ .as_ref()
+ .to_vec()
+ } else {
+ Metadata::new_of_type(MetadataType::KeyValueDataType)
+ .get_json_string()
+ .ok()?
+ .as_ref()
+ .to_vec()
+ };
+
+ let progress_ctx = match progress {
+ Some(mut x) => &mut x as *mut F as *mut std::ffi::c_void,
+ None => core::ptr::null_mut()
+ };
+
+ let handle = unsafe {
+ binaryninjacore_sys::BNLoadBinaryView(
+ bv.handle as *mut _,
+ update_analysis_and_wait,
+ options_or_default.as_ptr() as *mut core::ffi::c_char,
+ Some(cb_progress_func::<F>),
+ progress_ctx,
)
};
diff --git a/rust/src/update.rs b/rust/src/update.rs
index 026316f5..31e02cd8 100644
--- a/rust/src/update.rs
+++ b/rust/src/update.rs
@@ -100,7 +100,7 @@ impl UpdateChannel {
mut progress: F,
) -> Result<UpdateResult, BnString>
where
- F: FnMut(u64, u64) -> bool,
+ F: FnMut(usize, usize) -> bool,
{
let mut errors = ptr::null_mut();
let result = unsafe {
@@ -142,7 +142,7 @@ impl UpdateChannel {
mut progress: F,
) -> Result<UpdateResult, BnString>
where
- F: FnMut(u64, u64) -> bool,
+ F: FnMut(usize, usize) -> bool,
{
let mut errors = ptr::null_mut();
let result = unsafe {
@@ -256,16 +256,16 @@ pub fn updates_checked() {
unsafe extern "C" fn cb_progress_nop(
_ctxt: *mut ::std::os::raw::c_void,
- _progress: u64,
- _total: u64,
+ _progress: usize,
+ _total: usize,
) -> bool {
true
}
-unsafe extern "C" fn cb_progress<F: FnMut(u64, u64) -> bool>(
+unsafe extern "C" fn cb_progress<F: FnMut(usize, usize) -> bool>(
ctxt: *mut ::std::os::raw::c_void,
- progress: u64,
- total: u64,
+ progress: usize,
+ total: usize,
) -> bool {
let ctxt: &mut F = &mut *(ctxt as *mut F);
ctxt(progress, total)