From 9ce28f469edc9563488c52fecc8a60129cd75daa Mon Sep 17 00:00:00 2001 From: tinysec Date: Wed, 22 Jul 2026 17:30:01 +0800 Subject: [PATCH] feat: expose native IL form navigation --- Handle/BNBasicBlock.cs | 18 ++++++++--- Handle/BNHighLevelILFunction.cs | 54 ++++++++++++++++++++++++------- Handle/BNLowLevelILFunction.cs | 54 ++++++++++++++++++++++++------- Handle/BNMediumLevelILFunction.cs | 53 ++++++++++++++++++++++++++++-- ILFunctionNavigation.cs | 35 ++++++++++++++++++++ 5 files changed, 185 insertions(+), 29 deletions(-) create mode 100644 ILFunctionNavigation.cs diff --git a/Handle/BNBasicBlock.cs b/Handle/BNBasicBlock.cs index 2c27eb3b..f61fc6f3 100644 --- a/Handle/BNBasicBlock.cs +++ b/Handle/BNBasicBlock.cs @@ -50,8 +50,11 @@ public LowLevelILFunction? LowLevelIlFunction { get { + bool isSSAForm = FunctionGraphType.LowLevelILSSAFormFunctionGraph + == this.FunctionGraphType; return LowLevelILFunction.TakeHandle( - NativeMethods.BNGetBasicBlockLowLevelILFunction(this.handle) + NativeMethods.BNGetBasicBlockLowLevelILFunction(this.handle), + isSSAForm ); } } @@ -60,8 +63,12 @@ public MediumLevelILFunction? MediumLevelILFunction { get { + FunctionGraphType graphType = this.FunctionGraphType; + bool isSSAForm = FunctionGraphType.MediumLevelILSSAFormFunctionGraph == graphType + || FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph == graphType; return MediumLevelILFunction.TakeHandle( - NativeMethods.BNGetBasicBlockMediumLevelILFunction(this.handle) + NativeMethods.BNGetBasicBlockMediumLevelILFunction(this.handle), + isSSAForm ); } } @@ -70,8 +77,11 @@ public HighLevelILFunction? HighLevelILFunction { get { + bool isSSAForm = FunctionGraphType.HighLevelILSSAFormFunctionGraph + == this.FunctionGraphType; return HighLevelILFunction.TakeHandle( - NativeMethods.BNGetBasicBlockHighLevelILFunction(this.handle) + NativeMethods.BNGetBasicBlockHighLevelILFunction(this.handle), + isSSAForm ); } } @@ -811,4 +821,4 @@ ref length } } -} \ No newline at end of file +} diff --git a/Handle/BNHighLevelILFunction.cs b/Handle/BNHighLevelILFunction.cs index d66290b5..c9d87cd4 100644 --- a/Handle/BNHighLevelILFunction.cs +++ b/Handle/BNHighLevelILFunction.cs @@ -7,7 +7,23 @@ namespace BinaryNinja { public sealed class HighLevelILFunction : AbstractSafeHandle { - public bool IsSSAForm { get; } = false; + private readonly bool isSSAForm; + + /// + /// Gets whether this function is in SSA form. + /// + /// + /// Form-aware navigation sources propagate this value when creating the wrapper. Keeping + /// it as captured state avoids querying basic blocks while IL expression indices are in + /// use, because graph discovery can finalize lazy analysis state and shift those indices. + /// + public bool IsSSAForm + { + get + { + return this.isSSAForm; + } + } internal HighLevelILFunction( IntPtr handle , @@ -15,7 +31,15 @@ internal HighLevelILFunction( bool ssa = false ) : base(handle , owner) { - this.IsSSAForm = ssa; + this.isSSAForm = ssa; + } + + private static FunctionGraphType GetILForm(IntPtr functionHandle) + { + IntPtr blocks = NativeMethods.BNGetHighLevelILBasicBlockList( + functionHandle, + out ulong count); + return ILFunctionNavigation.TakeFunctionGraphType(blocks, count); } internal static HighLevelILFunction? NewFromHandle(IntPtr handle , bool ssa = false) @@ -856,18 +880,26 @@ public HighLevelILFlowGraph CreateImmediateGraph(DisassemblySettings? settings = ); } + /// + /// Gets the native IL form represented by this function. + /// + public FunctionGraphType ILForm + { + get + { + return GetILForm(this.handle); + } + } + + /// + /// Gets the native graph type. Use for parity with the official + /// bindings. + /// public FunctionGraphType FunctionGraphType { get { - if (this.BasicBlocks.Length < 1) - { - return FunctionGraphType.InvalidILViewType; - } - - return NativeMethods.BNGetBasicBlockFunctionGraphType( - this.BasicBlocks[0].DangerousGetHandle() - ); + return this.ILForm; } } @@ -1632,4 +1664,4 @@ public void UpdateOperand(ulong instr , ulong operandIndex , ulong value) ); } } -} \ No newline at end of file +} diff --git a/Handle/BNLowLevelILFunction.cs b/Handle/BNLowLevelILFunction.cs index d0f49309..2ee5cbc0 100644 --- a/Handle/BNLowLevelILFunction.cs +++ b/Handle/BNLowLevelILFunction.cs @@ -8,7 +8,23 @@ namespace BinaryNinja { public sealed class LowLevelILFunction : AbstractSafeHandle { - public bool IsSSAForm { get; } = false; + private readonly bool isSSAForm; + + /// + /// Gets whether this function is in SSA form. + /// + /// + /// Form-aware navigation sources propagate this value when creating the wrapper. Keeping + /// it as captured state avoids querying basic blocks while IL expression indices are in + /// use, because graph discovery can finalize lazy analysis state and shift those indices. + /// + public bool IsSSAForm + { + get + { + return this.isSSAForm; + } + } internal LowLevelILFunction( IntPtr handle , @@ -16,7 +32,15 @@ internal LowLevelILFunction( bool ssa = false ) : base(handle , owner) { - this.IsSSAForm = ssa; + this.isSSAForm = ssa; + } + + private static FunctionGraphType GetILForm(IntPtr functionHandle) + { + IntPtr blocks = NativeMethods.BNGetLowLevelILBasicBlockList( + functionHandle, + out ulong count); + return ILFunctionNavigation.TakeFunctionGraphType(blocks, count); } internal static LowLevelILFunction? NewFromHandle( @@ -440,18 +464,26 @@ public BinaryView View } } - public FunctionGraphType GraphType + /// + /// Gets the native IL form represented by this function. + /// + public FunctionGraphType ILForm { get { - if (this.BasicBlocks.Length < 1) - { - return FunctionGraphType.InvalidILViewType; - } + return GetILForm(this.handle); + } + } - return NativeMethods.BNGetBasicBlockFunctionGraphType( - this.BasicBlocks[0].DangerousGetHandle() - ); + /// + /// Gets the native graph type. Use for parity with the official + /// bindings. + /// + public FunctionGraphType GraphType + { + get + { + return this.ILForm; } } @@ -3318,4 +3350,4 @@ public LowLevelILExpressionIndex EmitIf( } -} \ No newline at end of file +} diff --git a/Handle/BNMediumLevelILFunction.cs b/Handle/BNMediumLevelILFunction.cs index 6349a94e..a7a4045d 100644 --- a/Handle/BNMediumLevelILFunction.cs +++ b/Handle/BNMediumLevelILFunction.cs @@ -11,7 +11,23 @@ namespace BinaryNinja { public sealed class MediumLevelILFunction : AbstractSafeHandle { - public bool IsSSAForm { get; } = false; + private readonly bool isSSAForm; + + /// + /// Gets whether this function is in either mapped or unmapped SSA form. + /// + /// + /// Form-aware navigation sources propagate this value when creating the wrapper. Keeping + /// it as captured state avoids querying basic blocks while IL expression indices are in + /// use, because graph discovery can finalize lazy analysis state and shift those indices. + /// + public bool IsSSAForm + { + get + { + return this.isSSAForm; + } + } internal MediumLevelILFunction( IntPtr handle , @@ -19,7 +35,15 @@ internal MediumLevelILFunction( bool ssa = false ) : base(handle , owner) { - this.IsSSAForm = ssa; + this.isSSAForm = ssa; + } + + private static FunctionGraphType GetILForm(IntPtr functionHandle) + { + IntPtr blocks = NativeMethods.BNGetMediumLevelILBasicBlockList( + functionHandle, + out ulong count); + return ILFunctionNavigation.TakeFunctionGraphType(blocks, count); } internal static MediumLevelILFunction? NewFromHandle( @@ -316,6 +340,29 @@ out ulong arrayLength } } + /// + /// Gets the native IL form represented by this function. + /// + public FunctionGraphType ILForm + { + get + { + return GetILForm(this.handle); + } + } + + /// + /// Gets the native graph type. This alias keeps the MLIL API consistent with the + /// existing LLIL and HLIL navigation properties. + /// + public FunctionGraphType FunctionGraphType + { + get + { + return this.ILForm; + } + } + public MediumLevelILBasicBlock? GetBasicBlockForInstruction(MediumLevelILInstructionIndex index) { return MediumLevelILBasicBlock.TakeHandleEx( @@ -3293,4 +3340,4 @@ public void UpdateOperand(ulong instr , ulong operandIndex , ulong value) } } -} \ No newline at end of file +} diff --git a/ILFunctionNavigation.cs b/ILFunctionNavigation.cs new file mode 100644 index 00000000..de434c9f --- /dev/null +++ b/ILFunctionNavigation.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; + +namespace BinaryNinja +{ + /// + /// Shared native-list handling for IL function form navigation. + /// + internal static class ILFunctionNavigation + { + /// + /// Takes ownership of a native basic-block list, reads its graph type, and frees the list. + /// + internal static FunctionGraphType TakeFunctionGraphType(IntPtr blocks, ulong count) + { + try + { + if (IntPtr.Zero == blocks || 0 == count) + { + return FunctionGraphType.InvalidILViewType; + } + + IntPtr firstBlock = Marshal.ReadIntPtr(blocks); + return NativeMethods.BNGetBasicBlockFunctionGraphType(firstBlock); + } + finally + { + if (IntPtr.Zero != blocks) + { + NativeMethods.BNFreeBasicBlockList(blocks, count); + } + } + } + } +}