diff options
| author | Mark Rowe <mark@vector35.com> | 2026-04-13 13:07:09 -0700 |
|---|---|---|
| committer | Mark Rowe <mark@vector35.com> | 2026-04-22 15:20:52 -0700 |
| commit | aa8dab21d44b4e0dd863f0867c7e735cfb878a4d (patch) | |
| tree | 256ca89364716afed1735521106130571b0fdb9b | |
| parent | 84d66dc7e6244e6ef78ebb3a2aa24b57a6ed4345 (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.h | 14 | ||||
| -rw-r--r-- | binaryninjacore.h | 2 | ||||
| -rw-r--r-- | binaryviewtype.cpp | 20 | ||||
| -rw-r--r-- | python/binaryview.py | 19 | ||||
| -rw-r--r-- | rust/src/custom_binary_view.rs | 26 | ||||
| -rw-r--r-- | view/kernelcache/core/KernelCacheView.h | 2 | ||||
| -rw-r--r-- | view/sharedcache/core/SharedCacheView.h | 2 |
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; }; |
