summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2026-04-13 13:07:09 -0700
committerMark Rowe <mark@vector35.com>2026-04-22 15:20:52 -0700
commitaa8dab21d44b4e0dd863f0867c7e735cfb878a4d (patch)
tree256ca89364716afed1735521106130571b0fdb9b
parent84d66dc7e6244e6ef78ebb3a2aa24b57a6ed4345 (diff)
Always show the triage view when opening a shared cache or kernel cache
BinaryViewType gains a HasNoInitialContent function that views can use to suppress layout restoration when opening a file. The layout will still be restored when the view is loaded from a saved database. Fixes https://github.com/Vector35/binaryninja-api/issues/8083.
-rw-r--r--binaryninjaapi.h14
-rw-r--r--binaryninjacore.h2
-rw-r--r--binaryviewtype.cpp20
-rw-r--r--python/binaryview.py19
-rw-r--r--rust/src/custom_binary_view.rs26
-rw-r--r--view/kernelcache/core/KernelCacheView.h2
-rw-r--r--view/sharedcache/core/SharedCacheView.h2
7 files changed, 85 insertions, 0 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index fe57d92d..1c482b66 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -8623,6 +8623,7 @@ namespace BinaryNinja {
static bool IsDeprecatedCallback(void* ctxt);
static bool IsForceLoadableCallback(void *ctxt);
static BNSettings* GetSettingsCallback(void* ctxt, BNBinaryView* data);
+ static bool HasNoInitialContentCallback(void* ctxt);
BinaryViewType(BNBinaryViewType* type);
@@ -8775,6 +8776,18 @@ namespace BinaryNinja {
*/
virtual bool IsForceLoadable();
+ /*! Check whether instances of this BinaryViewType start with no loaded content
+
+ When true, the view has no meaningful default state: the user must make a
+ selection (e.g. load images from a shared cache) before any content exists.
+ Callers can use this to suppress restoring previously-saved view state for
+ files not being loaded from a database, since a saved layout would reference
+ content that isn't available on reopen.
+
+ \return Whether instances of this BinaryViewType start with no loaded content
+ */
+ virtual bool HasNoInitialContent();
+
virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data);
Ref<Settings> GetDefaultLoadSettingsForData(BinaryView* data);
@@ -8798,6 +8811,7 @@ namespace BinaryNinja {
virtual bool IsTypeValidForData(BinaryView* data) override;
virtual bool IsDeprecated() override;
virtual bool IsForceLoadable() override;
+ virtual bool HasNoInitialContent() override;
virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data) override;
};
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 283524c8..446391e1 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -1888,6 +1888,7 @@ extern "C"
bool (*isDeprecated)(void* ctxt);
bool (*isForceLoadable)(void* ctxt);
BNSettings* (*getLoadSettingsForData)(void* ctxt, BNBinaryView* data);
+ bool (*hasNoInitialContent)(void* ctxt);
} BNCustomBinaryViewType;
typedef struct BNTransformParameterInfo
@@ -4801,6 +4802,7 @@ extern "C"
BINARYNINJACOREAPI BNBinaryView* BNParseBinaryViewOfType(BNBinaryViewType* type, BNBinaryView* data);
BINARYNINJACOREAPI bool BNIsBinaryViewTypeValidForData(BNBinaryViewType* type, BNBinaryView* data);
BINARYNINJACOREAPI bool BNIsBinaryViewTypeForceLoadable(BNBinaryViewType* type);
+ BINARYNINJACOREAPI bool BNBinaryViewTypeHasNoInitialContent(BNBinaryViewType* type);
BINARYNINJACOREAPI BNSettings* BNGetBinaryViewDefaultLoadSettingsForData(
BNBinaryViewType* type, BNBinaryView* data);
BINARYNINJACOREAPI BNSettings* BNGetBinaryViewLoadSettingsForData(BNBinaryViewType* type, BNBinaryView* data);
diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp
index f06218b1..dd542b2b 100644
--- a/binaryviewtype.cpp
+++ b/binaryviewtype.cpp
@@ -68,6 +68,13 @@ bool BinaryViewType::IsForceLoadableCallback(void* ctxt)
}
+bool BinaryViewType::HasNoInitialContentCallback(void* ctxt)
+{
+ CallbackRef<BinaryViewType> type(ctxt);
+ return type->HasNoInitialContent();
+}
+
+
BNSettings* BinaryViewType::GetSettingsCallback(void* ctxt, BNBinaryView* data)
{
CallbackRef<BinaryViewType> type(ctxt);
@@ -102,6 +109,7 @@ void BinaryViewType::Register(BinaryViewType* type)
callbacks.isDeprecated = IsDeprecatedCallback;
callbacks.isForceLoadable = IsForceLoadableCallback;
callbacks.getLoadSettingsForData = GetSettingsCallback;
+ callbacks.hasNoInitialContent = HasNoInitialContentCallback;
type->AddRefForRegistration();
type->m_object =
@@ -272,6 +280,12 @@ bool BinaryViewType::IsForceLoadable()
}
+bool BinaryViewType::HasNoInitialContent()
+{
+ return false;
+}
+
+
void BinaryViewType::RegisterBinaryViewFinalizationEvent(const function<void(BinaryView* view)>& callback)
{
BinaryViewEvent* event = new BinaryViewEvent;
@@ -378,6 +392,12 @@ bool CoreBinaryViewType::IsForceLoadable()
}
+bool CoreBinaryViewType::HasNoInitialContent()
+{
+ return BNBinaryViewTypeHasNoInitialContent(m_object);
+}
+
+
Ref<Settings> CoreBinaryViewType::GetLoadSettingsForData(BinaryView* data)
{
BNSettings* settings = BNGetBinaryViewLoadSettingsForData(m_object, data->GetObject());
diff --git a/python/binaryview.py b/python/binaryview.py
index 9368caa7..72768060 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -1514,6 +1514,11 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass):
"""returns if the BinaryViewType is force loadable (read-only)"""
return core.BNIsBinaryViewTypeForceLoadable(self.handle)
+ @property
+ def has_no_initial_content(self) -> bool:
+ """returns if instances of this BinaryViewType start with no loaded content (read-only)"""
+ return core.BNBinaryViewTypeHasNoInitialContent(self.handle)
+
def create(self, data: 'BinaryView') -> Optional['BinaryView']:
view = core.BNCreateBinaryViewOfType(self.handle, data.handle)
if view is None:
@@ -3328,6 +3333,9 @@ class BinaryView:
cls._registered_cb.getLoadSettingsForData = cls._registered_cb.getLoadSettingsForData.__class__(
cls._get_load_settings_for_data
)
+ cls._registered_cb.hasNoInitialContent = cls._registered_cb.hasNoInitialContent.__class__(
+ cls._has_no_initial_content
+ )
view_handle = core.BNRegisterBinaryViewType(cls.name, cls.long_name, cls._registered_cb)
assert view_handle is not None, "core.BNRegisterBinaryViewType returned None"
cls.registered_view_type = BinaryViewType(view_handle)
@@ -3405,6 +3413,17 @@ class BinaryView:
return False
@classmethod
+ def _has_no_initial_content(cls, ctxt):
+ if not callable(getattr(cls, 'has_no_initial_content', None)):
+ return False
+
+ try:
+ return cls.has_no_initial_content() # type: ignore
+ except:
+ log_error_for_exception("Unhandled Python exception in BinaryView._has_no_initial_content")
+ return False
+
+ @classmethod
def _get_load_settings_for_data(cls, ctxt, data):
try:
attr = getattr(cls, "get_load_settings_for_data", None)
diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs
index 8c880fc1..84f39171 100644
--- a/rust/src/custom_binary_view.rs
+++ b/rust/src/custom_binary_view.rs
@@ -75,6 +75,16 @@ where
})
}
+ extern "C" fn cb_has_no_initial_content<T>(ctxt: *mut c_void) -> bool
+ where
+ T: CustomBinaryViewType,
+ {
+ ffi_wrap!("BinaryViewTypeBase::has_no_initial_content", unsafe {
+ let view_type = &*(ctxt as *mut T);
+ view_type.has_no_initial_content()
+ })
+ }
+
extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
where
T: CustomBinaryViewType,
@@ -159,6 +169,7 @@ where
isDeprecated: Some(cb_deprecated::<T>),
isForceLoadable: Some(cb_force_loadable::<T>),
getLoadSettingsForData: Some(cb_load_settings::<T>),
+ hasNoInitialContent: Some(cb_has_no_initial_content::<T>),
};
unsafe {
@@ -199,6 +210,17 @@ pub trait BinaryViewTypeBase: AsRef<BinaryViewType> {
false
}
+ /// Do instances of this [`BinaryViewType`] start with no loaded content?
+ ///
+ /// When true, the view has no meaningful default state: the user must make a
+ /// selection (e.g. load images from a shared cache) before any content exists.
+ /// Callers can use this to suppress restoring previously-saved view state for
+ /// files not being loaded from a database, since a saved layout would reference
+ /// content that isn't available on reopen.
+ fn has_no_initial_content(&self) -> bool {
+ false
+ }
+
fn default_load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> {
let settings_handle =
unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().handle, data.handle) };
@@ -386,6 +408,10 @@ impl BinaryViewTypeBase for BinaryViewType {
unsafe { BNIsBinaryViewTypeForceLoadable(self.handle) }
}
+ fn has_no_initial_content(&self) -> bool {
+ unsafe { BNBinaryViewTypeHasNoInitialContent(self.handle) }
+ }
+
fn load_settings_for_data(&self, data: &BinaryView) -> Option<Ref<Settings>> {
let settings_handle =
unsafe { BNGetBinaryViewLoadSettingsForData(self.handle, data.handle) };
diff --git a/view/kernelcache/core/KernelCacheView.h b/view/kernelcache/core/KernelCacheView.h
index bfe12502..bb2515e4 100644
--- a/view/kernelcache/core/KernelCacheView.h
+++ b/view/kernelcache/core/KernelCacheView.h
@@ -54,6 +54,8 @@ public:
bool IsDeprecated() override { return false; }
+ bool HasNoInitialContent() override { return true; }
+
BinaryNinja::Ref<BinaryNinja::Settings> GetLoadSettingsForData(BinaryNinja::BinaryView* data) override;
};
diff --git a/view/sharedcache/core/SharedCacheView.h b/view/sharedcache/core/SharedCacheView.h
index ce592519..25f9591f 100644
--- a/view/sharedcache/core/SharedCacheView.h
+++ b/view/sharedcache/core/SharedCacheView.h
@@ -62,6 +62,8 @@ public:
bool IsDeprecated() override { return false; }
+ bool HasNoInitialContent() override { return true; }
+
BinaryNinja::Ref<BinaryNinja::Settings> GetLoadSettingsForData(BinaryNinja::BinaryView* data) override;
};