diff --git a/Architecture/BasicBlockAnalysisContext.cs b/Architecture/BasicBlockAnalysisContext.cs
new file mode 100644
index 0000000..82b9628
--- /dev/null
+++ b/Architecture/BasicBlockAnalysisContext.cs
@@ -0,0 +1,280 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace BinaryNinja
+{
+ ///
+ /// Provides the native-owned context passed to custom architecture basic-block analysis.
+ ///
+ public sealed class BasicBlockAnalysisContext
+ {
+ private readonly IntPtr handle;
+
+ internal BasicBlockAnalysisContext(IntPtr handle)
+ {
+ if (IntPtr.Zero == handle)
+ {
+ throw new ArgumentNullException(nameof(handle));
+ }
+
+ this.handle = handle;
+ }
+
+ internal IntPtr DangerousGetHandle()
+ {
+ return this.handle;
+ }
+
+ private BNBasicBlockAnalysisContext Native
+ {
+ get
+ {
+ return Marshal.PtrToStructure(this.handle);
+ }
+ }
+
+ ///
+ /// Gets an independently referenced wrapper for the function under analysis.
+ ///
+ public Function Function
+ {
+ get
+ {
+ return BinaryNinja.Function.MustNewFromHandle(this.Native.function);
+ }
+ }
+
+ public FunctionAnalysisSkipOverride AnalysisSkipOverride
+ {
+ get
+ {
+ return this.Native.analysisSkipOverride;
+ }
+ }
+
+ public bool GuidedAnalysisMode
+ {
+ get
+ {
+ return this.Native.guidedAnalysisMode;
+ }
+ }
+
+ public bool TriggerGuidedOnInvalidInstruction
+ {
+ get
+ {
+ return this.Native.triggerGuidedOnInvalidInstruction;
+ }
+ }
+
+ public bool TranslateTailCalls
+ {
+ get
+ {
+ return this.Native.translateTailCalls;
+ }
+ }
+
+ public bool DisallowBranchToString
+ {
+ get
+ {
+ return this.Native.disallowBranchToString;
+ }
+ }
+
+ public ulong MaxFunctionSize
+ {
+ get
+ {
+ return this.Native.maxFunctionSize;
+ }
+ }
+
+ public bool MaxSizeReached
+ {
+ get
+ {
+ return this.Native.maxSizeReached;
+ }
+ set
+ {
+ BNBasicBlockAnalysisContext native = this.Native;
+ native.maxSizeReached = value;
+ Marshal.StructureToPtr(native, this.handle, false);
+ }
+ }
+
+ public IndirectBranchInfo[] IndirectBranches
+ {
+ get
+ {
+ BNBasicBlockAnalysisContext native = this.Native;
+ return UnsafeUtils.ReadStructArray(
+ native.indirectBranches,
+ native.indirectBranchesCount,
+ IndirectBranchInfo.FromNative);
+ }
+ }
+
+ public ArchitectureAndAddress[] IndirectNoReturnCalls
+ {
+ get
+ {
+ BNBasicBlockAnalysisContext native = this.Native;
+ return UnsafeUtils.ReadStructArray<
+ BNArchitectureAndAddress,
+ ArchitectureAndAddress>(
+ native.indirectNoReturnCalls,
+ native.indirectNoReturnCallsCount,
+ ArchitectureAndAddress.FromNative);
+ }
+ }
+
+ public IntPtr FunctionArchitectureContext
+ {
+ get
+ {
+ return this.Native.functionArchContext;
+ }
+ set
+ {
+ BNBasicBlockAnalysisContext native = this.Native;
+ if (IntPtr.Zero != native.functionArchContext)
+ {
+ throw new InvalidOperationException(
+ "The function architecture context has already been set.");
+ }
+
+ native.functionArchContext = value;
+ Marshal.StructureToPtr(native, this.handle, false);
+ }
+ }
+
+ public BasicBlock? CreateBasicBlock(Architecture architecture, ulong address)
+ {
+ if (null == architecture)
+ {
+ throw new ArgumentNullException(nameof(architecture));
+ }
+
+ return AnalyzeBasicBlocksContext.CreateBasicBlock(
+ this.handle,
+ architecture,
+ address);
+ }
+
+ public void AddBasicBlock(BasicBlock block)
+ {
+ if (null == block)
+ {
+ throw new ArgumentNullException(nameof(block));
+ }
+
+ AnalyzeBasicBlocksContext.AddBasicBlockToFunction(this.handle, block);
+ }
+
+ public void AddTemporaryOutgoingReference(Function target)
+ {
+ if (null == target)
+ {
+ throw new ArgumentNullException(nameof(target));
+ }
+
+ AnalyzeBasicBlocksContext.AddTempReference(this.handle, target);
+ }
+
+ public void SetContextualFunctionReturns(
+ ArchitectureAndAddress[] sources,
+ bool[] values)
+ {
+ if (null == sources)
+ {
+ throw new ArgumentNullException(nameof(sources));
+ }
+
+ if (null == values)
+ {
+ throw new ArgumentNullException(nameof(values));
+ }
+
+ if (sources.Length != values.Length)
+ {
+ throw new ArgumentException(
+ "Sources and values must contain the same number of entries.");
+ }
+
+ AnalyzeBasicBlocksContext.SetContextualFunctionReturns(
+ this.handle,
+ sources,
+ values);
+ }
+
+ public void SetDirectCodeReferences(
+ ArchitectureAndAddress[] sources,
+ ulong[] targets)
+ {
+ if (null == sources)
+ {
+ throw new ArgumentNullException(nameof(sources));
+ }
+
+ if (null == targets)
+ {
+ throw new ArgumentNullException(nameof(targets));
+ }
+
+ if (sources.Length != targets.Length)
+ {
+ throw new ArgumentException(
+ "Sources and targets must contain the same number of entries.");
+ }
+
+ AnalyzeBasicBlocksContext.SetDirectCodeReferences(
+ this.handle,
+ sources,
+ targets);
+ }
+
+ public void SetDirectNoReturnCalls(ArchitectureAndAddress[] sources)
+ {
+ if (null == sources)
+ {
+ throw new ArgumentNullException(nameof(sources));
+ }
+
+ AnalyzeBasicBlocksContext.SetDirectNoReturnCalls(this.handle, sources);
+ }
+
+ public void SetHaltedDisassemblyAddresses(ArchitectureAndAddress[] sources)
+ {
+ if (null == sources)
+ {
+ throw new ArgumentNullException(nameof(sources));
+ }
+
+ AnalyzeBasicBlocksContext.SetHaltedDisassemblyAddresses(this.handle, sources);
+ }
+
+ public void SetInlinedUnresolvedIndirectBranches(
+ ArchitectureAndAddress[] sourceAndDestinationPairs)
+ {
+ if (null == sourceAndDestinationPairs)
+ {
+ throw new ArgumentNullException(nameof(sourceAndDestinationPairs));
+ }
+
+ if (0 != sourceAndDestinationPairs.Length % 2)
+ {
+ throw new ArgumentException(
+ "Source and destination locations must be provided in pairs.",
+ nameof(sourceAndDestinationPairs));
+ }
+
+ AnalyzeBasicBlocksContext.SetInlinedUnresolvedIndirectBranches(
+ this.handle,
+ sourceAndDestinationPairs);
+ }
+ }
+}
diff --git a/Architecture/CustomArchitectureAnalysisCallbacks.cs b/Architecture/CustomArchitectureAnalysisCallbacks.cs
new file mode 100644
index 0000000..eaa2ec3
--- /dev/null
+++ b/Architecture/CustomArchitectureAnalysisCallbacks.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace BinaryNinja
+{
+ public abstract partial class CustomArchitecture
+ {
+ [UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
+ private delegate void AnalyzeBasicBlocksCallback(
+ IntPtr context,
+ IntPtr function,
+ IntPtr analysisContext);
+
+ private void AddAnalysisCallbacks(ref BNCustomArchitecture callbacks)
+ {
+ callbacks.analyzeBasicBlocks = UnsafeUtils.PinCallback(
+ this.AnalyzeBasicBlocksAdapter);
+ }
+
+ private void AnalyzeBasicBlocksAdapter(
+ IntPtr context,
+ IntPtr functionHandle,
+ IntPtr analysisContextHandle)
+ {
+ try
+ {
+ using (Function function = Function.MustNewFromHandle(functionHandle))
+ {
+ BasicBlockAnalysisContext analysisContext =
+ new BasicBlockAnalysisContext(analysisContextHandle);
+ this.AnalyzeBasicBlocks(function, analysisContext);
+ }
+ }
+ catch (Exception exception)
+ {
+ Core.LogError(
+ "Unhandled exception in CustomArchitecture.AnalyzeBasicBlocks: {0}",
+ exception);
+ }
+ }
+ }
+}
diff --git a/Architecture/CustomArchitectureRegistration.cs b/Architecture/CustomArchitectureRegistration.cs
index 8936d4e..ee84897 100644
--- a/Architecture/CustomArchitectureRegistration.cs
+++ b/Architecture/CustomArchitectureRegistration.cs
@@ -65,6 +65,7 @@ public Architecture Register(string name)
this.AddAssemblyAndPatchCallbacks(ref callbacks);
this.AddIntrinsicCallbacks(ref callbacks);
this.AddFlagLoweringCallbacks(ref callbacks);
+ this.AddAnalysisCallbacks(ref callbacks);
using (ScopedAllocator allocator = new ScopedAllocator())
{
diff --git a/Struct/BNBasicBlockAnalysisContext.cs b/Struct/BNBasicBlockAnalysisContext.cs
index 7294cbf..51849f5 100644
--- a/Struct/BNBasicBlockAnalysisContext.cs
+++ b/Struct/BNBasicBlockAnalysisContext.cs
@@ -1,231 +1,47 @@
using System;
-using System.Collections.Generic;
using System.Runtime.InteropServices;
-using Microsoft.Win32.SafeHandles;
namespace BinaryNinja
{
[StructLayout(LayoutKind.Sequential)]
- internal unsafe struct BNBasicBlockAnalysisContext
+ internal struct BNBasicBlockAnalysisContext
{
- ///
- /// BNFunction* function
- ///
- public IntPtr function;
-
- ///
- /// BNFunctionAnalysisSkipOverride analysisSkipOverride
- ///
- public FunctionAnalysisSkipOverride analysisSkipOverride;
-
- ///
- /// bool guidedAnalysisMode
- ///
- [MarshalAs(UnmanagedType.I1)] public bool guidedAnalysisMode;
-
- ///
- /// bool triggerGuidedOnInvalidInstruction
- ///
- [MarshalAs(UnmanagedType.I1)] public bool triggerGuidedOnInvalidInstruction;
-
- ///
- /// bool translateTailCalls
- ///
- [MarshalAs(UnmanagedType.I1)] public bool translateTailCalls;
-
- ///
- /// bool disallowBranchToString
- ///
- [MarshalAs(UnmanagedType.I1)] public bool disallowBranchToString;
-
- ///
- /// uint64_t maxFunctionSize
- ///
- public ulong maxFunctionSize;
-
- ///
- /// uint64_t indirectBranchesCount
- ///
- public ulong indirectBranchesCount;
-
- ///
- /// BNIndirectBranchInfo* indirectBranches
- ///
- public IntPtr indirectBranches;
-
- ///
- /// uint64_t indirectNoReturnCallsCount
- ///
- public ulong indirectNoReturnCallsCount;
-
- ///
- /// BNArchitectureAndAddress* indirectNoReturnCalls
- ///
- public IntPtr indirectNoReturnCalls;
-
- ///
- /// bool maxSizeReached
- ///
- [MarshalAs(UnmanagedType.I1)] public bool maxSizeReached;
-
- ///
- /// uint64_t contextualFunctionReturnCount
- ///
- public ulong contextualFunctionReturnCount;
-
- ///
- /// BNArchitectureAndAddress* contextualFunctionReturnLocations
- ///
- public IntPtr contextualFunctionReturnLocations;
-
- ///
- /// bool* contextualFunctionReturnValues
- ///
- public IntPtr contextualFunctionReturnValues;
-
- ///
- /// uint64_t directRefCount
- ///
- public ulong directRefCount;
-
- ///
- /// BNArchitectureAndAddress* directRefSources
- ///
- public IntPtr directRefSources;
-
- ///
- /// uint64_t* directRefTargets
- ///
- public IntPtr directRefTargets;
-
- ///
- /// uint64_t directNoReturnCallsCount
- ///
- public ulong directNoReturnCallsCount;
-
- ///
- /// BNArchitectureAndAddress* directNoReturnCalls
- ///
- public IntPtr directNoReturnCalls;
-
- ///
- /// uint64_t haltedDisassemblyAddressesCount
- ///
- public ulong haltedDisassemblyAddressesCount;
-
- ///
- /// BNArchitectureAndAddress* haltedDisassemblyAddresses
- ///
- public IntPtr haltedDisassemblyAddresses;
-
- ///
- /// uint64_t inlinedUnresolvedIndirectBranchCount
- ///
- public ulong inlinedUnresolvedIndirectBranchCount;
-
- ///
- /// BNArchitectureAndAddress* inlinedUnresolvedIndirectBranches
- ///
- public IntPtr inlinedUnresolvedIndirectBranches;
- }
+ internal IntPtr function;
+ internal FunctionAnalysisSkipOverride analysisSkipOverride;
+
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool guidedAnalysisMode;
+
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool triggerGuidedOnInvalidInstruction;
+
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool translateTailCalls;
- public class BasicBlockAnalysisContext
- {
- public Function? Function { get; set; } = null;
-
- public FunctionAnalysisSkipOverride AnalysisSkipOverride { get; set; } =
- FunctionAnalysisSkipOverride.DefaultFunctionAnalysisSkip;
-
- public bool GuidedAnalysisMode { get; set; } = false;
-
- public bool TriggerGuidedOnInvalidInstruction { get; set; } = false;
-
- public bool TranslateTailCalls { get; set; } = false;
-
- public bool DisallowBranchToString { get; set; } = false;
-
- public ulong MaxFunctionSize { get; set; } = 0;
-
- public ulong IndirectBranchesCount { get; set; } = 0;
-
- ///
- /// BNIndirectBranchInfo* indirectBranches
- ///
- public IntPtr IndirectBranches { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t indirectNoReturnCallsCount
- ///
- public ulong IndirectNoReturnCallsCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* indirectNoReturnCalls
- ///
- public IntPtr IndirectNoReturnCalls { get; set; } = IntPtr.Zero;
-
- public bool MaxSizeReached { get; set; } = false;
-
- public ulong ContextualFunctionReturnCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* contextualFunctionReturnLocations
- ///
- public IntPtr ContextualFunctionReturnLocations { get; set; } = IntPtr.Zero;
-
- ///
- /// bool* contextualFunctionReturnValues
- ///
- public IntPtr ContextualFunctionReturnValues { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t directRefCount
- ///
- public ulong DirectRefCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* directRefSources
- ///
- public IntPtr DirectRefSources { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t* directRefTargets
- ///
- public IntPtr DirectRefTargets { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t directNoReturnCallsCount
- ///
- public ulong DirectNoReturnCallsCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* directNoReturnCalls
- ///
- public IntPtr DirectNoReturnCalls { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t haltedDisassemblyAddressesCount
- ///
- public ulong HaltedDisassemblyAddressesCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* haltedDisassemblyAddresses
- ///
- public IntPtr HaltedDisassemblyAddresses { get; set; } = IntPtr.Zero;
-
- ///
- /// uint64_t inlinedUnresolvedIndirectBranchCount
- ///
- public ulong InlinedUnresolvedIndirectBranchCount { get; set; } = 0;
-
- ///
- /// BNArchitectureAndAddress* inlinedUnresolvedIndirectBranches
- ///
- public IntPtr InlinedUnresolvedIndirectBranches { get; set; } = IntPtr.Zero;
-
-
- public BasicBlockAnalysisContext()
- {
-
- }
- }
-}
\ No newline at end of file
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool disallowBranchToString;
+
+ internal ulong maxFunctionSize;
+ internal ulong indirectBranchesCount;
+ internal IntPtr indirectBranches;
+ internal ulong indirectNoReturnCallsCount;
+ internal IntPtr indirectNoReturnCalls;
+
+ [MarshalAs(UnmanagedType.I1)]
+ internal bool maxSizeReached;
+
+ internal ulong contextualFunctionReturnCount;
+ internal IntPtr contextualFunctionReturnLocations;
+ internal IntPtr contextualFunctionReturnValues;
+ internal ulong directRefCount;
+ internal IntPtr directRefSources;
+ internal IntPtr directRefTargets;
+ internal ulong directNoReturnCallsCount;
+ internal IntPtr directNoReturnCalls;
+ internal ulong haltedDisassemblyAddressesCount;
+ internal IntPtr haltedDisassemblyAddresses;
+ internal ulong inlinedUnresolvedIndirectBranchCount;
+ internal IntPtr inlinedUnresolvedIndirectBranches;
+ internal IntPtr functionArchContext;
+ }
+}
diff --git a/Struct/BNCustomArchitecture.cs b/Struct/BNCustomArchitecture.cs
index e5f629a..ccbc3ae 100644
--- a/Struct/BNCustomArchitecture.cs
+++ b/Struct/BNCustomArchitecture.cs
@@ -671,6 +671,18 @@ LowLevelILFunction il
{
return null;
}
+
+ ///
+ /// Analyzes a function's basic blocks using the core-owned analysis context.
+ ///
+ public virtual void AnalyzeBasicBlocks(
+ Function function,
+ BasicBlockAnalysisContext context)
+ {
+ NativeMethods.BNArchitectureDefaultAnalyzeBasicBlocks(
+ function.DangerousGetHandle(),
+ context.DangerousGetHandle());
+ }
public virtual string GetRegisterName(
RegisterIndex reg