diff --git a/Handle/BNAnalysisContext.cs b/Handle/BNAnalysisContext.cs index fa70a3f..db8799c 100644 --- a/Handle/BNAnalysisContext.cs +++ b/Handle/BNAnalysisContext.cs @@ -13,7 +13,7 @@ namespace BinaryNinja /// Analysis passes use the context to retrieve IL functions, inspect lifted code, and /// communicate structured requests back to the analysis pipeline via Inform(). /// - public sealed class AnalysisContext : AbstractSafeHandle + public sealed partial class AnalysisContext : AbstractSafeHandle { /// /// Initializes a new AnalysisContext wrapper around an existing native handle. @@ -357,21 +357,7 @@ public static AnalysisContext Create() /// The Medium Level IL function to set. public void SetMediumLevelILFunction(MediumLevelILFunction mlilFunction) { - // 1. Validate the required parameter. - if (null == mlilFunction) - { - throw new ArgumentNullException(nameof(mlilFunction)); - } - - // 2. Forward to the native API with empty mapping arrays. - NativeMethods.BNSetMediumLevelILFunction( - this.handle , - mlilFunction.DangerousGetHandle() , - IntPtr.Zero , - 0 , - IntPtr.Zero , - 0 - ); + this.SetMediumLevelILFunction(mlilFunction, null, null); } // --------------------------------------------------------------------- diff --git a/Handle/BNMediumLevelILFunction.cs b/Handle/BNMediumLevelILFunction.cs index a7a4045..d093c31 100644 --- a/Handle/BNMediumLevelILFunction.cs +++ b/Handle/BNMediumLevelILFunction.cs @@ -9,7 +9,7 @@ namespace BinaryNinja { - public sealed class MediumLevelILFunction : AbstractSafeHandle + public sealed partial class MediumLevelILFunction : AbstractSafeHandle { private readonly bool isSSAForm; @@ -541,6 +541,12 @@ Variable[] knownAliases public void PrepareToCopyFunction(MediumLevelILFunction source) { + if (null == source) + { + throw new ArgumentNullException(nameof(source)); + } + + this.BeginTranslation(source); NativeMethods.BNPrepareToCopyMediumLevelILFunction(this.handle , source.DangerousGetHandle()); } @@ -759,18 +765,20 @@ MediumLevelILExpressionIndex mediumExpr { return null; } + + LowLevelILFunction llilSSA = llil.SSAForm; LowLevelILExpressionIndex lowExpr = NativeMethods.BNGetLowLevelILExprIndex( this.handle, mediumExpr ); - if ((ulong)lowExpr >= llil.ExpressionCount) + if ((ulong)lowExpr >= llilSSA.ExpressionCount) { return null; } - return llil.GetExpression(lowExpr); + return llilSSA.GetExpression(lowExpr); } public LowLevelILInstruction? GetLowLevelILInstruction( @@ -783,18 +791,20 @@ MediumLevelILInstructionIndex mediumInstr { return null; } + + LowLevelILFunction llilSSA = llil.SSAForm; LowLevelILInstructionIndex lowInstr = NativeMethods.BNGetLowLevelILInstructionIndex( this.handle, mediumInstr ); - if ((ulong)lowInstr >= llil.InstructionCount) + if ((ulong)lowInstr >= llilSSA.InstructionCount) { return null; } - return llil.GetInstruction(lowInstr); + return llilSSA.GetInstruction(lowInstr); } public LowLevelILInstruction[] GetLowLevelILExpressions( @@ -807,6 +817,8 @@ MediumLevelILExpressionIndex mediumExpr { return Array.Empty(); } + + LowLevelILFunction llilSSA = llil.SSAForm; IntPtr arrayPointer = NativeMethods.BNGetLowLevelILExprIndexes( this.handle, @@ -825,7 +837,7 @@ out ulong arrayLength foreach (LowLevelILExpressionIndex lowExpr in lowExprs) { expressions.Add( - llil.MustGetExpression(lowExpr) + llilSSA.MustGetExpression(lowExpr) ); } @@ -1102,9 +1114,15 @@ public void SetExpressionAttributes(MediumLevelILExpressionIndex expr , uint att NativeMethods.BNSetMediumLevelILExprAttributes(this.handle , expr , attributes); } - public MediumLevelILInstructionIndex AddInstruction(MediumLevelILExpressionIndex expr) + public MediumLevelILInstructionIndex AddInstruction( + MediumLevelILExpressionIndex expr, + SourceLocation? location = null) { - return NativeMethods.BNMediumLevelILAddInstruction(this.handle , expr); + MediumLevelILInstructionIndex result = + NativeMethods.BNMediumLevelILAddInstruction(this.handle , expr); + this.RecordInstructionTranslation(result, location); + + return result; } public PossibleValueSet GetSSAVariablePossibleValues( @@ -1555,6 +1573,7 @@ public MediumLevelILExpressionIndex AddExpression( params ulong[] operands ) { + MediumLevelILExpressionIndex result; ulong a = 0; ulong b = 0; ulong c = 0; @@ -1588,7 +1607,7 @@ params ulong[] operands if (null == location) { - return NativeMethods.BNMediumLevelILAddExpr( + result = NativeMethods.BNMediumLevelILAddExpr( this.handle , operation, size , @@ -1601,7 +1620,7 @@ params ulong[] operands } else { - return NativeMethods.BNMediumLevelILAddExprWithLocation( + result = NativeMethods.BNMediumLevelILAddExprWithLocation( this.handle , operation, location.Address, @@ -1614,7 +1633,10 @@ params ulong[] operands e ); } - + + this.RecordExpressionTranslation(result, location); + + return result; } public MediumLevelILExpressionIndex EmitNop(SourceLocation? location = null) diff --git a/IL/SourceLocation.cs b/IL/SourceLocation.cs index ddfac70..4635023 100644 --- a/IL/SourceLocation.cs +++ b/IL/SourceLocation.cs @@ -9,6 +9,26 @@ public sealed class SourceLocation : IEquatable, public OperandIndex Operand { get; } = 0; + /// + /// Gets the source LLIL instruction when this location was derived from LLIL. + /// + public LowLevelILInstruction? SourceLowLevelILInstruction { get; private set; } + + /// + /// Gets the source MLIL instruction when this location was derived from MLIL. + /// + public MediumLevelILInstruction? SourceMediumLevelILInstruction { get; private set; } + + /// + /// Gets the source HLIL instruction when this location was derived from HLIL. + /// + public HighLevelILInstruction? SourceHighLevelILInstruction { get; private set; } + + /// + /// Gets whether the source IL instruction maps directly to the generated expression. + /// + public bool ILDirect { get; private set; } = true; + public SourceLocation() { @@ -19,6 +39,78 @@ public SourceLocation(ulong address, OperandIndex operand) this.Address = address; this.Operand = operand; } + + private SourceLocation( + ulong address, + OperandIndex operand, + bool ilDirect) + : this(address, operand) + { + this.ILDirect = ilDirect; + } + + /// + /// Creates a source location derived from an LLIL instruction. + /// + public static SourceLocation FromInstruction( + LowLevelILInstruction instruction, + bool ilDirect = true) + { + if (null == instruction) + { + throw new ArgumentNullException(nameof(instruction)); + } + + SourceLocation result = new SourceLocation( + instruction.Address, + instruction.SourceOperand, + ilDirect); + result.SourceLowLevelILInstruction = instruction; + + return result; + } + + /// + /// Creates a source location derived from an MLIL instruction. + /// + public static SourceLocation FromInstruction( + MediumLevelILInstruction instruction, + bool ilDirect = true) + { + if (null == instruction) + { + throw new ArgumentNullException(nameof(instruction)); + } + + SourceLocation result = new SourceLocation( + instruction.Address, + instruction.SourceOperand, + ilDirect); + result.SourceMediumLevelILInstruction = instruction; + + return result; + } + + /// + /// Creates a source location derived from an HLIL instruction. + /// + public static SourceLocation FromInstruction( + HighLevelILInstruction instruction, + bool ilDirect = true) + { + if (null == instruction) + { + throw new ArgumentNullException(nameof(instruction)); + } + + SourceLocation result = new SourceLocation( + instruction.Address, + instruction.SourceOperand, + ilDirect); + result.SourceHighLevelILInstruction = instruction; + + return result; + } public override bool Equals(object? other) { diff --git a/MediumLevelIL/AnalysisContextMLILMapping.cs b/MediumLevelIL/AnalysisContextMLILMapping.cs new file mode 100644 index 0000000..6a87d2e --- /dev/null +++ b/MediumLevelIL/AnalysisContextMLILMapping.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; + +namespace BinaryNinja +{ + /// + /// MLIL mapping support for analysis-context translation activities. + /// + public sealed partial class AnalysisContext + { + /// + /// Sets the MLIL function and its LLIL SSA instruction/expression mappings. + /// When either mapping is omitted, both are rebuilt from the source-aware locations recorded + /// after by + /// and + /// . + /// + public void SetMediumLevelILFunction( + MediumLevelILFunction mlilFunction, + IReadOnlyDictionary? + instructionMap, + IReadOnlyList? expressionMap) + { + if (null == mlilFunction) + { + throw new ArgumentNullException(nameof(mlilFunction)); + } + + IReadOnlyDictionary + effectiveInstructionMap; + IReadOnlyList effectiveExpressionMap; + + if (null == instructionMap || null == expressionMap) + { + effectiveInstructionMap = + mlilFunction.GetLLILSSAToMLILInstructionMap(true); + effectiveExpressionMap = + mlilFunction.GetLLILSSAToMLILExpressionMap(true); + } + else + { + effectiveInstructionMap = instructionMap; + effectiveExpressionMap = expressionMap; + } + + ulong[] nativeInstructionMap = BuildInstructionMap(effectiveInstructionMap); + BNExprMapInfo[] nativeExpressionMap = BuildExpressionMap(effectiveExpressionMap); + + using (ScopedAllocator allocator = new ScopedAllocator()) + { + IntPtr instructionMapPointer = + allocator.AllocStructArray(nativeInstructionMap); + IntPtr expressionMapPointer = + allocator.AllocStructArray(nativeExpressionMap); + + NativeMethods.BNSetMediumLevelILFunction( + this.handle, + mlilFunction.DangerousGetHandle(), + instructionMapPointer, + (ulong)nativeInstructionMap.Length, + expressionMapPointer, + (ulong)nativeExpressionMap.Length); + } + } + + private static ulong[] BuildInstructionMap( + IReadOnlyDictionary mapping) + { + ulong highestIndex = 0; + bool hasEntries = false; + + foreach (KeyValuePair entry + in mapping) + { + ulong rawIndex = (ulong)entry.Key; + if (ulong.MaxValue == rawIndex) + { + throw new ArgumentOutOfRangeException( + nameof(mapping), + "The invalid LLIL instruction index cannot be used as a mapping key."); + } + + if (!hasEntries || highestIndex < rawIndex) + { + highestIndex = rawIndex; + } + + hasEntries = true; + } + + if (!hasEntries) + { + return Array.Empty(); + } + + if ((ulong)(int.MaxValue - 1) < highestIndex) + { + throw new ArgumentOutOfRangeException( + nameof(mapping), + "The LLIL instruction mapping is too large for a managed array."); + } + + ulong[] result = new ulong[(int)highestIndex + 1]; + for (int index = 0; index < result.Length; index++) + { + result[index] = ulong.MaxValue; + } + + foreach (KeyValuePair entry + in mapping) + { + result[(int)(ulong)entry.Key] = (ulong)entry.Value; + } + + return result; + } + + private static BNExprMapInfo[] BuildExpressionMap( + IReadOnlyList mapping) + { + BNExprMapInfo[] result = new BNExprMapInfo[mapping.Count]; + + for (int index = 0; index < mapping.Count; index++) + { + LLILSSAToMLILExpressionMap? entry = mapping[index]; + if (null == entry) + { + throw new ArgumentException( + "The expression mapping cannot contain null entries.", + nameof(mapping)); + } + + result[index] = entry.ToNative(); + } + + return result; + } + } +} diff --git a/MediumLevelIL/MediumLevelILTranslation.cs b/MediumLevelIL/MediumLevelILTranslation.cs new file mode 100644 index 0000000..db7e9fc --- /dev/null +++ b/MediumLevelIL/MediumLevelILTranslation.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections.Generic; + +namespace BinaryNinja +{ + /// + /// Managed translation state used to reproduce the official MLIL-to-MLIL mapping pipeline. + /// + public sealed partial class MediumLevelILFunction + { + private sealed class ExpressionTranslationTarget + { + public MediumLevelILExpressionIndex ExpressionIndex { get; } + + public bool Direct { get; } + + public ExpressionTranslationTarget( + MediumLevelILExpressionIndex expressionIndex, + bool direct) + { + this.ExpressionIndex = expressionIndex; + this.Direct = direct; + } + } + + private sealed class InstructionTranslationTarget + { + public MediumLevelILInstructionIndex InstructionIndex { get; } + + public bool Direct { get; } + + public InstructionTranslationTarget( + MediumLevelILInstructionIndex instructionIndex, + bool direct) + { + this.InstructionIndex = instructionIndex; + this.Direct = direct; + } + } + + private MediumLevelILFunction? translationSourceFunction; + + private readonly Dictionary> + expressionTranslations = + new Dictionary>(); + + private readonly Dictionary> + instructionTranslations = + new Dictionary>(); + + private void BeginTranslation(MediumLevelILFunction source) + { + this.translationSourceFunction = source; + this.expressionTranslations.Clear(); + this.instructionTranslations.Clear(); + } + + private void RecordExpressionTranslation( + MediumLevelILExpressionIndex expressionIndex, + SourceLocation? location) + { + if (null == this.translationSourceFunction || null == location) + { + return; + } + + MediumLevelILInstruction? source = location.SourceMediumLevelILInstruction; + if (null == source) + { + return; + } + + MediumLevelILExpressionIndex sourceIndex = source.ExpressionIndex; + if (!this.expressionTranslations.TryGetValue( + sourceIndex, + out List? targets)) + { + targets = new List(); + this.expressionTranslations.Add(sourceIndex, targets); + } + + targets.Add(new ExpressionTranslationTarget(expressionIndex, location.ILDirect)); + } + + private void RecordInstructionTranslation( + MediumLevelILInstructionIndex instructionIndex, + SourceLocation? location) + { + if (null == this.translationSourceFunction || null == location) + { + return; + } + + MediumLevelILInstruction? source = location.SourceMediumLevelILInstruction; + if (null == source) + { + return; + } + + MediumLevelILInstructionIndex sourceIndex = source.InstructionIndex; + if (!this.instructionTranslations.TryGetValue( + sourceIndex, + out List? targets)) + { + targets = new List(); + this.instructionTranslations.Add(sourceIndex, targets); + } + + targets.Add(new InstructionTranslationTarget(instructionIndex, location.ILDirect)); + } + + /// + /// Gets the LLIL SSA instruction-to-MLIL instruction mapping accumulated by a translation, + /// or reconstructs the installed mapping from this function when requested. + /// + public Dictionary + GetLLILSSAToMLILInstructionMap(bool fromTranslation = true) + { + Dictionary result = + new Dictionary(); + + if (fromTranslation) + { + this.BuildTranslatedInstructionMap(result); + } + else + { + this.BuildInstalledInstructionMap(result); + } + + return result; + } + + private void BuildTranslatedInstructionMap( + Dictionary result) + { + MediumLevelILFunction? sourceFunction = this.translationSourceFunction; + if (null == sourceFunction) + { + return; + } + + foreach (KeyValuePair> entry + in this.instructionTranslations) + { + LowLevelILInstructionIndex lowerIndex = + NativeMethods.BNGetLowLevelILInstructionIndex( + sourceFunction.DangerousGetHandle(), + entry.Key); + + if (LowLevelILInstructionIndex.Invalid == lowerIndex) + { + continue; + } + + foreach (InstructionTranslationTarget target in entry.Value) + { + if (target.Direct) + { + result[lowerIndex] = target.InstructionIndex; + } + } + } + } + + private void BuildInstalledInstructionMap( + Dictionary result) + { + for (ulong rawIndex = 0; rawIndex < this.InstructionCount; rawIndex++) + { + MediumLevelILInstructionIndex higherIndex = + (MediumLevelILInstructionIndex)rawIndex; + LowLevelILInstructionIndex lowerIndex = + NativeMethods.BNGetLowLevelILInstructionIndex( + this.DangerousGetHandle(), + higherIndex); + + if (LowLevelILInstructionIndex.Invalid != lowerIndex) + { + result[lowerIndex] = higherIndex; + } + } + } + + /// + /// Gets the LLIL SSA expression-to-MLIL expression mapping accumulated by a translation, + /// or reconstructs the installed mapping from this function when requested. + /// + public List GetLLILSSAToMLILExpressionMap( + bool fromTranslation = true) + { + List result = + new List(); + + if (fromTranslation) + { + this.BuildTranslatedExpressionMap(result); + } + else + { + this.BuildInstalledExpressionMap(result); + } + + return result; + } + + private void BuildTranslatedExpressionMap(List result) + { + MediumLevelILFunction? sourceFunction = this.translationSourceFunction; + if (null == sourceFunction) + { + return; + } + + LowLevelILFunction? sourceLowLevelIL = sourceFunction.LowLevelIL; + if (null == sourceLowLevelIL) + { + return; + } + + LowLevelILFunction sourceLowLevelILSSA = sourceLowLevelIL.SSAForm; + + foreach (KeyValuePair> entry + in this.expressionTranslations) + { + foreach (ExpressionTranslationTarget target in entry.Value) + { + AppendExpressionMappings( + sourceFunction, + sourceLowLevelILSSA, + entry.Key, + target.ExpressionIndex, + target.Direct, + result); + } + } + } + + private void BuildInstalledExpressionMap(List result) + { + LowLevelILFunction? sourceLowLevelIL = this.LowLevelIL; + if (null == sourceLowLevelIL) + { + return; + } + + LowLevelILFunction sourceLowLevelILSSA = sourceLowLevelIL.SSAForm; + + foreach (MediumLevelILInstruction instruction in this.Instructions) + { + foreach (MediumLevelILInstruction expression in instruction.Traverse(ReturnInstruction)) + { + AppendExpressionMappings( + this, + sourceLowLevelILSSA, + expression.ExpressionIndex, + expression.ExpressionIndex, + true, + result); + } + } + } + + private static MediumLevelILInstruction ReturnInstruction( + MediumLevelILInstruction instruction) + { + return instruction; + } + + private static void AppendExpressionMappings( + MediumLevelILFunction mappingFunction, + LowLevelILFunction lowerSSAFunction, + MediumLevelILExpressionIndex sourceExpressionIndex, + MediumLevelILExpressionIndex targetExpressionIndex, + bool targetIsDirect, + List result) + { + LowLevelILExpressionIndex directLowerIndex = NativeMethods.BNGetLowLevelILExprIndex( + mappingFunction.DangerousGetHandle(), + sourceExpressionIndex); + LowLevelILExpressionIndex[] lowerIndexes = GetLowLevelExpressionIndexes( + mappingFunction, + sourceExpressionIndex); + + foreach (LowLevelILExpressionIndex lowerIndex in lowerIndexes) + { + MediumLevelILExpressionIndex directHigherIndex = + NativeMethods.BNGetMediumLevelILExprIndex( + lowerSSAFunction.DangerousGetHandle(), + lowerIndex); + MediumLevelILExpressionIndex[] higherIndexes = GetMediumLevelExpressionIndexes( + lowerSSAFunction, + lowerIndex); + + bool mapsLowerToHigher = ContainsExpressionIndex( + higherIndexes, + sourceExpressionIndex); + bool lowerToHigherDirect = targetIsDirect + && directHigherIndex == sourceExpressionIndex; + bool higherToLowerDirect = targetIsDirect + && lowerIndex == directLowerIndex; + + result.Add(new LLILSSAToMLILExpressionMap( + lowerIndex, + targetExpressionIndex, + mapsLowerToHigher, + true, + lowerToHigherDirect, + higherToLowerDirect)); + } + } + + private static LowLevelILExpressionIndex[] GetLowLevelExpressionIndexes( + MediumLevelILFunction function, + MediumLevelILExpressionIndex expressionIndex) + { + IntPtr arrayPointer = NativeMethods.BNGetLowLevelILExprIndexes( + function.DangerousGetHandle(), + expressionIndex, + out ulong arrayLength); + + return UnsafeUtils.TakeNumberArray( + arrayPointer, + arrayLength, + NativeMethods.BNFreeILInstructionList); + } + + private static MediumLevelILExpressionIndex[] GetMediumLevelExpressionIndexes( + LowLevelILFunction function, + LowLevelILExpressionIndex expressionIndex) + { + IntPtr arrayPointer = NativeMethods.BNGetMediumLevelILExprIndexes( + function.DangerousGetHandle(), + expressionIndex, + out ulong arrayLength); + + return UnsafeUtils.TakeNumberArray( + arrayPointer, + arrayLength, + NativeMethods.BNFreeILInstructionList); + } + + private static bool ContainsExpressionIndex( + MediumLevelILExpressionIndex[] indexes, + MediumLevelILExpressionIndex expected) + { + foreach (MediumLevelILExpressionIndex index in indexes) + { + if (expected == index) + { + return true; + } + } + + return false; + } + } +} diff --git a/Struct/BNExprMapInfo.cs b/Struct/BNExprMapInfo.cs index e098d68..5088bc1 100644 --- a/Struct/BNExprMapInfo.cs +++ b/Struct/BNExprMapInfo.cs @@ -57,5 +57,57 @@ public ExprMapInfo() { } + + public ExprMapInfo( + ulong lowerIndex, + ulong higherIndex, + bool mapLowerToHigher, + bool mapHigherToLower, + bool lowerToHigherDirect, + bool higherToLowerDirect) + { + this.LowerIndex = lowerIndex; + this.HigherIndex = higherIndex; + this.MapLowerToHigher = mapLowerToHigher; + this.MapHigherToLower = mapHigherToLower; + this.LowerToHigherDirect = lowerToHigherDirect; + this.HigherToLowerDirect = higherToLowerDirect; + } + + internal BNExprMapInfo ToNative() + { + return new BNExprMapInfo + { + lowerIndex = this.LowerIndex, + higherIndex = this.HigherIndex, + mapLowerToHigher = this.MapLowerToHigher, + mapHigherToLower = this.MapHigherToLower, + lowerToHigherDirect = this.LowerToHigherDirect, + higherToLowerDirect = this.HigherToLowerDirect, + }; + } } -} \ No newline at end of file + + /// + /// Describes one LLIL SSA expression to MLIL expression mapping. + /// + public sealed class LLILSSAToMLILExpressionMap : ExprMapInfo + { + public LLILSSAToMLILExpressionMap( + LowLevelILExpressionIndex lowerIndex, + MediumLevelILExpressionIndex higherIndex, + bool mapLowerToHigher, + bool mapHigherToLower, + bool lowerToHigherDirect, + bool higherToLowerDirect) + : base( + (ulong)lowerIndex, + (ulong)higherIndex, + mapLowerToHigher, + mapHigherToLower, + lowerToHigherDirect, + higherToLowerDirect) + { + } + } +} diff --git a/Struct/BNHighLevelILInstruction.cs b/Struct/BNHighLevelILInstruction.cs index 8703b77..7fbd073 100644 --- a/Struct/BNHighLevelILInstruction.cs +++ b/Struct/BNHighLevelILInstruction.cs @@ -59,8 +59,19 @@ public abstract partial class HighLevelILInstruction : public ulong RawParent { get; } = 0; public OperandIndex SourceOperand { get; } = 0; - + public ulong Address { get; } = 0; + + /// + /// Gets a source-aware location suitable for IL translation builders. + /// + public SourceLocation Location + { + get + { + return SourceLocation.FromInstruction(this); + } + } public ulong[] RawOperands { get; } = Array.Empty(); diff --git a/Struct/BNLowLevelILInstruction.cs b/Struct/BNLowLevelILInstruction.cs index f66153b..28c4998 100644 --- a/Struct/BNLowLevelILInstruction.cs +++ b/Struct/BNLowLevelILInstruction.cs @@ -409,7 +409,7 @@ public SourceLocation Location { get { - return new SourceLocation(this.Address , this.SourceOperand); + return SourceLocation.FromInstruction(this); } } @@ -2124,4 +2124,4 @@ public void SetSourceOperand(uint operand) ); } } -} \ No newline at end of file +} diff --git a/Struct/BNMediumLevelILInstruction.cs b/Struct/BNMediumLevelILInstruction.cs index b2cc0b8..6b276a9 100644 --- a/Struct/BNMediumLevelILInstruction.cs +++ b/Struct/BNMediumLevelILInstruction.cs @@ -54,6 +54,17 @@ public abstract class MediumLevelILInstruction public OperandIndex SourceOperand { get; } = 0; public ulong Address { get; } = 0; + + /// + /// Gets a source-aware location suitable for MLIL translation builders. + /// + public SourceLocation Location + { + get + { + return SourceLocation.FromInstruction(this); + } + } public ulong[] RawOperands { get; }= Array.Empty();