diff options
| -rw-r--r-- | binaryninjaapi.h | 28 | ||||
| -rw-r--r-- | binaryninjacore.h | 32 | ||||
| -rw-r--r-- | function.cpp | 27 | ||||
| -rw-r--r-- | plugins/workflow_objc/src/activities/inline_stubs.rs | 4 | ||||
| -rw-r--r-- | python/function.py | 41 | ||||
| -rw-r--r-- | python/types.py | 35 | ||||
| -rw-r--r-- | rust/src/confidence.rs | 21 | ||||
| -rw-r--r-- | rust/src/function.rs | 9 | ||||
| -rw-r--r-- | view/sharedcache/workflow/SharedCacheWorkflow.cpp | 2 |
9 files changed, 157 insertions, 42 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index db54a9a8..e28ebfb1 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -13139,6 +13139,8 @@ namespace BinaryNinja { bool GetInstructionContainingAddress(Architecture* arch, uint64_t addr, uint64_t* start); Confidence<bool> IsInlinedDuringAnalysis(); + Confidence<BNInlineDuringAnalysis> GetInlinedDuringAnalysis(); + /*! Set whether the function should be inlined during analysis. This will take effect if the new confidence level is higher than the confidence @@ -13148,8 +13150,30 @@ namespace BinaryNinja { \param inlined Whether the function should be inlined. */ - void SetAutoInlinedDuringAnalysis(Confidence<bool> inlined); - void SetUserInlinedDuringAnalysis(Confidence<bool> inlined); + void SetAutoInlinedDuringAnalysis(Confidence<BNInlineDuringAnalysis> inlined); + void SetUserInlinedDuringAnalysis(Confidence<BNInlineDuringAnalysis> inlined); + + // These overloads are needed to disambiguate calls that pass enum values directly. + void SetAutoInlinedDuringAnalysis(BNInlineDuringAnalysis inlined) { SetAutoInlinedDuringAnalysis(Confidence(inlined)); } + void SetUserInlinedDuringAnalysis(BNInlineDuringAnalysis inlined) { SetUserInlinedDuringAnalysis(Confidence(inlined)); } + + /*! + \deprecated Use the overload that takes `BNInlineDuringAnalysis`. + */ + void SetAutoInlinedDuringAnalysis(Confidence<bool> inlined) + { + BNInlineDuringAnalysis value = inlined.GetValue() ? InlinePreservingTargetInstructionAddresses : DoNotInlineCall; + SetAutoInlinedDuringAnalysis(Confidence(value, inlined.GetConfidence())); + }; + + /*! + \deprecated Use the overload that takes `BNInlineDuringAnalysis`. + */ + void SetUserInlinedDuringAnalysis(Confidence<bool> inlined) + { + BNInlineDuringAnalysis value = inlined.GetValue() ? InlinePreservingTargetInstructionAddresses : DoNotInlineCall; + SetUserInlinedDuringAnalysis(Confidence(value, inlined.GetConfidence())); + }; // TODO: Documentation bool IsInstructionCollapsed(const HighLevelILInstruction& instr, uint64_t designator = 0) const; diff --git a/binaryninjacore.h b/binaryninjacore.h index 8144ed7e..1e346bb1 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1131,6 +1131,33 @@ extern "C" MemoryIntrinsicClass }; + BN_ENUM(uint8_t, BNInlineDuringAnalysis) + { + // The called function should not be inlined. + DoNotInlineCall, + + // The called function should be inlined, with the inlined + // instructions preserving their original addresses. + // This was the only behavior available up through Binary Ninja 5.2. + InlinePreservingTargetInstructionAddresses, + + // The called function should be inlined, with the inlined + // instructions using the call site address as their address. + // This ensures that when the function is inlined into a caller + // multiple times, each occurrence can have different adjustments + // applied to it. The trade-off is that the instructions inlined + // at a given call site have the same address, which in turn + // prevents applying adjustments that depend on instruction + // address to only a subset of those instructions. + InlineUsingCallAddress, + }; + + typedef struct BNInlineDuringAnalysisWithConfidence + { + BNInlineDuringAnalysis value; + uint8_t confidence; + } BNInlineDuringAnalysisWithConfidence; + typedef struct BNLowLevelILInstruction { BNLowLevelILOperation operation; @@ -5175,8 +5202,9 @@ extern "C" BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionRegisterValueAtExit(BNFunction* func, uint32_t reg); BINARYNINJACOREAPI BNBoolWithConfidence BNIsFunctionInlinedDuringAnalysis(BNFunction* func); - BINARYNINJACOREAPI void BNSetAutoFunctionInlinedDuringAnalysis(BNFunction* func, BNBoolWithConfidence inlined); - BINARYNINJACOREAPI void BNSetUserFunctionInlinedDuringAnalysis(BNFunction* func, BNBoolWithConfidence inlined); + BINARYNINJACOREAPI BNInlineDuringAnalysisWithConfidence BNGetFunctionInlinedDuringAnalysis(BNFunction* func); + BINARYNINJACOREAPI void BNSetAutoFunctionInlinedDuringAnalysis(BNFunction* func, BNInlineDuringAnalysisWithConfidence inlined); + BINARYNINJACOREAPI void BNSetUserFunctionInlinedDuringAnalysis(BNFunction* func, BNInlineDuringAnalysisWithConfidence inlined); BINARYNINJACOREAPI bool BNGetInstructionContainingAddress( BNFunction* func, BNArchitecture* arch, uint64_t addr, uint64_t* start); diff --git a/function.cpp b/function.cpp index d5e692de..3f5f5b2e 100644 --- a/function.cpp +++ b/function.cpp @@ -3230,21 +3230,28 @@ Confidence<bool> Function::IsInlinedDuringAnalysis() } -void Function::SetAutoInlinedDuringAnalysis(Confidence<bool> inlined) +Confidence<BNInlineDuringAnalysis> Function::GetInlinedDuringAnalysis() { - BNBoolWithConfidence bc; - bc.value = inlined.GetValue(); - bc.confidence = inlined.GetConfidence(); - BNSetAutoFunctionInlinedDuringAnalysis(m_object, bc); + BNInlineDuringAnalysisWithConfidence value = BNGetFunctionInlinedDuringAnalysis(m_object); + return Confidence(value.value, value.confidence); } -void Function::SetUserInlinedDuringAnalysis(Confidence<bool> inlined) +void Function::SetAutoInlinedDuringAnalysis(Confidence<BNInlineDuringAnalysis> inlined) { - BNBoolWithConfidence bc; - bc.value = inlined.GetValue(); - bc.confidence = inlined.GetConfidence(); - BNSetUserFunctionInlinedDuringAnalysis(m_object, bc); + BNInlineDuringAnalysisWithConfidence value; + value.value = inlined.GetValue(); + value.confidence = inlined.GetConfidence(); + BNSetAutoFunctionInlinedDuringAnalysis(m_object, value); +} + + +void Function::SetUserInlinedDuringAnalysis(Confidence<BNInlineDuringAnalysis> inlined) +{ + BNInlineDuringAnalysisWithConfidence value; + value.value = inlined.GetValue(); + value.confidence = inlined.GetConfidence(); + BNSetUserFunctionInlinedDuringAnalysis(m_object, value); } diff --git a/plugins/workflow_objc/src/activities/inline_stubs.rs b/plugins/workflow_objc/src/activities/inline_stubs.rs index daae9baa..8ddb2fa3 100644 --- a/plugins/workflow_objc/src/activities/inline_stubs.rs +++ b/plugins/workflow_objc/src/activities/inline_stubs.rs @@ -1,4 +1,4 @@ -use binaryninja::workflow::AnalysisContext; +use binaryninja::{function::InlineDuringAnalysis, workflow::AnalysisContext}; use crate::{metadata::GlobalState, Error}; @@ -19,7 +19,7 @@ pub fn process(ac: &AnalysisContext) -> Result<(), Error> { }; if objc_stubs.contains(&func.start()) { - func.set_auto_inline_during_analysis(true); + func.set_auto_inline_during_analysis(InlineDuringAnalysis::InlineUsingCallAddress); } Ok(()) diff --git a/python/function.py b/python/function.py index c328ca77..29527f4d 100644 --- a/python/function.py +++ b/python/function.py @@ -1667,13 +1667,13 @@ class Function: return self.view.get_function_parent_components(self) @property - def inline_during_analysis(self) -> 'types.BoolWithConfidence': + def inline_during_analysis(self) -> 'types.InlineDuringAnalysisWithConfidence': """Whether the function's IL should be inlined into all callers' IL""" - result = core.BNIsFunctionInlinedDuringAnalysis(self.handle) - return types.BoolWithConfidence(result.value, confidence=result.confidence) + result = core.BNGetFunctionInlinedDuringAnalysis(self.handle) + return types.InlineDuringAnalysisWithConfidence(result.value, confidence=result.confidence) @inline_during_analysis.setter - def inline_during_analysis(self, value: Union[bool, 'types.BoolWithConfidence']): + def inline_during_analysis(self, value: Union['types.InlineDuringAnalysis', 'types.InlineDuringAnalysisWithConfidence', bool, 'types.BoolWithConfidence']): self.set_user_inline_during_analysis(value) def mark_recent_use(self) -> None: @@ -3553,23 +3553,26 @@ class Function: """ core.BNUnsplitVariable(self.handle, var.to_BNVariable()) - def set_auto_inline_during_analysis(self, value: Union[bool, 'types.BoolWithConfidence']): - bc = core.BNBoolWithConfidence() - bc.value = bool(value) - if isinstance(value, types.BoolWithConfidence): - bc.confidence = value.confidence - else: - bc.confidence = core.max_confidence - core.BNSetAutoFunctionInlinedDuringAnalysis(self.handle, bc) + @classmethod + def _inline_during_analysis_with_confidence(cls, value: Union['types.InlineDuringAnalysis', 'types.InlineDuringAnalysisWithConfidence', bool, 'types.BoolWithConfidence']) -> 'types.InlineDuringAnalysisWithConfidence': + if isinstance(value, types.InlineDuringAnalysisWithConfidence): + return value - def set_user_inline_during_analysis(self, value: Union[bool, 'types.BoolWithConfidence']): - bc = core.BNBoolWithConfidence() - bc.value = bool(value) if isinstance(value, types.BoolWithConfidence): - bc.confidence = value.confidence - else: - bc.confidence = core.max_confidence - core.BNSetUserFunctionInlinedDuringAnalysis(self.handle, bc) + return core.BNInlineDuringAnalysisWithConfidence(int(value.value), value.confidence) + + if isinstance(value, bool): + return core.BNInlineDuringAnalysisWithConfidence(int(value), core.max_confidence) + + return core.BNInlineDuringAnalysisWithConfidence(value, core.max_confidence) + + def set_auto_inline_during_analysis(self, value: Union['types.InlineDuringAnalysis', 'types.InlineDuringAnalysisWithConfidence', bool, 'types.BoolWithConfidence']): + value = self._inline_during_analysis_with_confidence(value) + core.BNSetAutoFunctionInlinedDuringAnalysis(self.handle, value) + + def set_user_inline_during_analysis(self, value: Union['types.InlineDuringAnalysis', 'types.InlineDuringAnalysisWithConfidence', bool, 'types.BoolWithConfidence']): + value = self._inline_during_analysis_with_confidence(value) + core.BNSetUserFunctionInlinedDuringAnalysis(self.handle, value) def toggle_region(self, hash): """ diff --git a/python/types.py b/python/types.py index a47f531d..44583c4d 100644 --- a/python/types.py +++ b/python/types.py @@ -27,7 +27,7 @@ import uuid # Binary Ninja components from . import _binaryninjacore as core from .enums import ( - StructureVariant, SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, + InlineDuringAnalysis, StructureVariant, SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, ReferenceType, VariableSourceType, TypeReferenceType, MemberAccess, MemberScope, TypeDefinitionLineType, TokenEscapingType, @@ -528,6 +528,39 @@ class BoolWithConfidence: return BoolWithConfidence(value, confidence)._to_core_struct() +@dataclass(frozen=True) +class InlineDuringAnalysisWithConfidence: + """Represents an InlineDuringAnalysis value with an associated confidence level.""" + value: InlineDuringAnalysis + confidence: int = core.max_confidence + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # For backward compatibility, allow comparison with bool + if isinstance(other, bool): + return bool(self.value) == other + # Allow comparison with enum value directly + return self.value == other + else: + return (self.value, self.confidence) == (other.value, other.confidence) + + def __ne__(self, other): + return not (self == other) + + def __bool__(self): + return bool(self.value) + + def _to_core_struct(self) -> core.BNInlineDuringAnalysisWithConfidence: + result = core.BNInlineDuringAnalysisWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct: core.BNInlineDuringAnalysisWithConfidence) -> 'InlineDuringAnalysisWithConfidence': + return cls(InlineDuringAnalysis(core_struct.value), core_struct.confidence) + + @dataclass class MutableTypeBuilder(Generic[TB]): type: TB diff --git a/rust/src/confidence.rs b/rust/src/confidence.rs index fd0b5532..f8745180 100644 --- a/rust/src/confidence.rs +++ b/rust/src/confidence.rs @@ -6,7 +6,8 @@ use crate::rc::{Ref, RefCountable}; use crate::types::Type; use binaryninjacore_sys::{ BNBoolWithConfidence, BNCallingConventionWithConfidence, BNGetCallingConventionArchitecture, - BNOffsetWithConfidence, BNTypeWithConfidence, + BNInlineDuringAnalysis, BNInlineDuringAnalysisWithConfidence, BNOffsetWithConfidence, + BNTypeWithConfidence, }; use std::fmt; use std::fmt::{Debug, Display, Formatter}; @@ -280,6 +281,15 @@ impl From<BNOffsetWithConfidence> for Conf<i64> { } } +impl From<BNInlineDuringAnalysisWithConfidence> for Conf<BNInlineDuringAnalysis> { + fn from(inline_with_confidence: BNInlineDuringAnalysisWithConfidence) -> Self { + Self::new( + inline_with_confidence.value, + inline_with_confidence.confidence, + ) + } +} + impl From<Conf<bool>> for BNBoolWithConfidence { fn from(conf: Conf<bool>) -> Self { Self { @@ -297,3 +307,12 @@ impl From<Conf<i64>> for BNOffsetWithConfidence { } } } + +impl From<Conf<BNInlineDuringAnalysis>> for BNInlineDuringAnalysisWithConfidence { + fn from(conf: Conf<BNInlineDuringAnalysis>) -> Self { + Self { + value: conf.contents, + confidence: conf.confidence, + } + } +} diff --git a/rust/src/function.rs b/rust/src/function.rs index e5516d14..c19e2107 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -36,6 +36,7 @@ pub use binaryninjacore_sys::BNBuiltinType as BuiltinType; pub use binaryninjacore_sys::BNFunctionAnalysisSkipOverride as FunctionAnalysisSkipOverride; pub use binaryninjacore_sys::BNFunctionUpdateType as FunctionUpdateType; pub use binaryninjacore_sys::BNHighlightStandardColor as HighlightStandardColor; +pub use binaryninjacore_sys::BNInlineDuringAnalysis as InlineDuringAnalysis; use crate::architecture::{IndirectBranchInfo, RegisterId}; use crate::binary_view::AddressRange; @@ -1127,17 +1128,17 @@ impl Function { pub fn set_auto_inline_during_analysis<C>(&self, value: C) where - C: Into<Conf<bool>>, + C: Into<Conf<InlineDuringAnalysis>>, { - let value: Conf<bool> = value.into(); + let value: Conf<InlineDuringAnalysis> = value.into(); unsafe { BNSetAutoFunctionInlinedDuringAnalysis(self.handle, value.into()) } } pub fn set_user_inline_during_analysis<C>(&self, value: C) where - C: Into<Conf<bool>>, + C: Into<Conf<InlineDuringAnalysis>>, { - let value: Conf<bool> = value.into(); + let value: Conf<InlineDuringAnalysis> = value.into(); unsafe { BNSetUserFunctionInlinedDuringAnalysis(self.handle, value.into()) } } diff --git a/view/sharedcache/workflow/SharedCacheWorkflow.cpp b/view/sharedcache/workflow/SharedCacheWorkflow.cpp index dcdf6c23..2b9cd28b 100644 --- a/view/sharedcache/workflow/SharedCacheWorkflow.cpp +++ b/view/sharedcache/workflow/SharedCacheWorkflow.cpp @@ -199,7 +199,7 @@ void AnalyzeStubFunction(Ref<Function> func, Ref<MediumLevelILFunction> mlil, Sh { case MLIL_CONST_PTR: // NOTE: This runs every single function update. - func->SetAutoInlinedDuringAnalysis(true); + func->SetAutoInlinedDuringAnalysis(InlineUsingCallAddress); break; default: break; |
