From e21e76bac0645ff878f29305a0b4a7fc5762deef Mon Sep 17 00:00:00 2001 From: Ahmed Garhy Date: Tue, 11 Aug 2015 22:56:44 -0500 Subject: [PATCH] + Deprecated old native instruction collection and enumerator + Updated documentation and code for new deferred instruction enumerator --- Capstone.NET.sln | 18 - CapstoneCMD/Program.cs | 20 +- Gee.External.Capstone/CapstoneDisassembler.cs | 320 +++++++++++++----- .../Gee.External.Capstone.csproj | 1 + .../NativeInstructionCollection.cs | 1 + .../NativeInstructionCollectionEnumerator.cs | 1 + 6 files changed, 243 insertions(+), 118 deletions(-) diff --git a/Capstone.NET.sln b/Capstone.NET.sln index 8fcd108..c939a75 100644 --- a/Capstone.NET.sln +++ b/Capstone.NET.sln @@ -17,42 +17,24 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution .NET4Debug|x86 = .NET4Debug|x86 .NET4Release|x86 = .NET4Release|x86 - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1297DCEE-009D-4739-8124-3F064EA9EA10}..NET4Debug|x86.ActiveCfg = .NET45Release|x86 {1297DCEE-009D-4739-8124-3F064EA9EA10}..NET4Debug|x86.Build.0 = .NET45Release|x86 {1297DCEE-009D-4739-8124-3F064EA9EA10}..NET4Release|x86.ActiveCfg = .NET45Release|x86 {1297DCEE-009D-4739-8124-3F064EA9EA10}..NET4Release|x86.Build.0 = .NET45Release|x86 - {1297DCEE-009D-4739-8124-3F064EA9EA10}.Debug|x86.ActiveCfg = .NET45Debug|x86 - {1297DCEE-009D-4739-8124-3F064EA9EA10}.Debug|x86.Build.0 = .NET45Debug|x86 - {1297DCEE-009D-4739-8124-3F064EA9EA10}.Release|x86.ActiveCfg = .NET45Release|x86 - {1297DCEE-009D-4739-8124-3F064EA9EA10}.Release|x86.Build.0 = .NET45Release|x86 {7D755424-C594-4605-820D-9AF880E091BC}..NET4Debug|x86.ActiveCfg = .NET45Release|x86 {7D755424-C594-4605-820D-9AF880E091BC}..NET4Debug|x86.Build.0 = .NET45Release|x86 {7D755424-C594-4605-820D-9AF880E091BC}..NET4Release|x86.ActiveCfg = .NET45Release|x86 {7D755424-C594-4605-820D-9AF880E091BC}..NET4Release|x86.Build.0 = .NET45Release|x86 - {7D755424-C594-4605-820D-9AF880E091BC}.Debug|x86.ActiveCfg = .NET45Debug|x86 - {7D755424-C594-4605-820D-9AF880E091BC}.Debug|x86.Build.0 = .NET45Debug|x86 - {7D755424-C594-4605-820D-9AF880E091BC}.Release|x86.ActiveCfg = .NET45Release|x86 - {7D755424-C594-4605-820D-9AF880E091BC}.Release|x86.Build.0 = .NET45Release|x86 {D1A6EC03-1420-4516-8548-4117A18DA8B3}..NET4Debug|x86.ActiveCfg = .NET45Release|x86 {D1A6EC03-1420-4516-8548-4117A18DA8B3}..NET4Debug|x86.Build.0 = .NET45Release|x86 {D1A6EC03-1420-4516-8548-4117A18DA8B3}..NET4Release|x86.ActiveCfg = .NET45Release|x86 {D1A6EC03-1420-4516-8548-4117A18DA8B3}..NET4Release|x86.Build.0 = .NET45Release|x86 - {D1A6EC03-1420-4516-8548-4117A18DA8B3}.Debug|x86.ActiveCfg = .NET45Debug|x86 - {D1A6EC03-1420-4516-8548-4117A18DA8B3}.Debug|x86.Build.0 = .NET45Debug|x86 - {D1A6EC03-1420-4516-8548-4117A18DA8B3}.Release|x86.ActiveCfg = .NET45Release|x86 - {D1A6EC03-1420-4516-8548-4117A18DA8B3}.Release|x86.Build.0 = .NET45Release|x86 {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}..NET4Debug|x86.ActiveCfg = .NET4Debug|x86 {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}..NET4Debug|x86.Build.0 = .NET4Debug|x86 {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}..NET4Release|x86.ActiveCfg = .NET4Release|x86 {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}..NET4Release|x86.Build.0 = .NET4Release|x86 - {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}.Debug|x86.ActiveCfg = .NET4Debug|x86 - {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}.Debug|x86.Build.0 = .NET4Debug|x86 - {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}.Release|x86.ActiveCfg = .NET4Release|x86 - {D8E7BF01-1424-4312-AF14-982E7DA9B9BC}.Release|x86.Build.0 = .NET4Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CapstoneCMD/Program.cs b/CapstoneCMD/Program.cs index d02246f..4db958e 100644 --- a/CapstoneCMD/Program.cs +++ b/CapstoneCMD/Program.cs @@ -32,7 +32,7 @@ internal static void Main(string[] args) { Program.ShowArm(DisassembleMode.Arm32); break; case "ARM32-V8": - Program.ShowArm((int)DisassembleMode.Arm32 + DisassembleMode.ArmV8); + Program.ShowArm((int) DisassembleMode.Arm32 + DisassembleMode.ArmV8); break; case "ARM32-Thumb": Program.ShowArm(DisassembleMode.ArmThumb); @@ -74,16 +74,16 @@ internal static void ShowArm(DisassembleMode mode) { var code = new byte[0]; switch (mode) { case DisassembleMode.Arm32: - code = new byte[] {0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5, 0xf1, 0x02, 0x03, 0x0e, 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x30, 0xc1, 0xe7, 0x00, 0x00, 0x53, 0xe3, 0x00, 0x02, 0x01, 0xf1, 0x05, 0x40, 0xd0, 0xe8, 0xf4, 0x80, 0x00, 0x00}; + code = new byte[] { 0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5, 0xf1, 0x02, 0x03, 0x0e, 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x30, 0xc1, 0xe7, 0x00, 0x00, 0x53, 0xe3, 0x00, 0x02, 0x01, 0xf1, 0x05, 0x40, 0xd0, 0xe8, 0xf4, 0x80, 0x00, 0x00 }; break; - case (int)DisassembleMode.Arm32 + DisassembleMode.ArmV8: + case (int) DisassembleMode.Arm32 + DisassembleMode.ArmV8: code = new byte[] { 0xe0, 0x3b, 0xb2, 0xee, 0x42, 0x00, 0x01, 0xe1, 0x51, 0xf0, 0x7f, 0xf5 }; break; case DisassembleMode.ArmThumb: - code = new byte[] {0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68, 0x1f, 0xb1, 0x30, 0xbf, 0xaf, 0xf3, 0x20, 0x84}; + code = new byte[] { 0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68, 0x1f, 0xb1, 0x30, 0xbf, 0xaf, 0xf3, 0x20, 0x84 }; break; case (int) DisassembleMode.ArmThumb + DisassembleMode.ArmCortexM: - code = new byte[] {0xef, 0xf3, 0x02, 0x80}; + code = new byte[] { 0xef, 0xf3, 0x02, 0x80 }; break; } @@ -194,7 +194,7 @@ internal static void ShowArm64() { // Disassemble All Binary Code. // // ... - var code = new byte[] {0x09, 0x00, 0x38, 0xd5, 0xbf, 0x40, 0x00, 0xd5, 0x0c, 0x05, 0x13, 0xd5, 0x20, 0x50, 0x02, 0x0e, 0x20, 0xe4, 0x3d, 0x0f, 0x00, 0x18, 0xa0, 0x5f, 0xa2, 0x00, 0xae, 0x9e, 0x9f, 0x37, 0x03, 0xd5, 0xbf, 0x33, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9, 0x20, 0x04, 0x81, 0xda, 0x20, 0x08, 0x02, 0x8b, 0x10, 0x5b, 0xe8, 0x3c}; + var code = new byte[] { 0x09, 0x00, 0x38, 0xd5, 0xbf, 0x40, 0x00, 0xd5, 0x0c, 0x05, 0x13, 0xd5, 0x20, 0x50, 0x02, 0x0e, 0x20, 0xe4, 0x3d, 0x0f, 0x00, 0x18, 0xa0, 0x5f, 0xa2, 0x00, 0xae, 0x9e, 0x9f, 0x37, 0x03, 0xd5, 0xbf, 0x33, 0x03, 0xd5, 0xdf, 0x3f, 0x03, 0xd5, 0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9, 0x20, 0x04, 0x81, 0xda, 0x20, 0x08, 0x02, 0x8b, 0x10, 0x5b, 0xe8, 0x3c }; var instructions = disassembler.DisassembleAll(code, 0x2C); var hexCode = BitConverter.ToString(code).Replace("-", " "); @@ -327,11 +327,11 @@ internal static void ShowX86() { // Disassemble All Binary Code. // // ... - var code = new byte[] {0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00, 0x05, 0x23, 0x01, 0x00, 0x00, 0x36, 0x8b, 0x84, 0x91, 0x23, 0x01, 0x00, 0x00, 0x41, 0x8d, 0x84, 0x39, 0x89, 0x67, 0x00, 0x00, 0x8d, 0x87, 0x89, 0x67, 0x00, 0x00, 0xb4, 0xc6}; + var code = new byte[] { 0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00, 0x05, 0x23, 0x01, 0x00, 0x00, 0x36, 0x8b, 0x84, 0x91, 0x23, 0x01, 0x00, 0x00, 0x41, 0x8d, 0x84, 0x39, 0x89, 0x67, 0x00, 0x00, 0x8d, 0x87, 0x89, 0x67, 0x00, 0x00, 0xb4, 0xc6 }; #if DISASSEMBLE_STREAM - //$REVIEW: uxmal: This exercises the lazy stream implementation of the disassembler. - // It isn't greed and tries to disassembly all the instructions at once, - // but only on demand. + //$REVIEW: uxmal: This exercises the lazy stream implementation of the disassembler. + // It isn't greed and tries to disassembly all the instructions at once, + // but only on demand. var instructions = disassembler.DisassembleStream(code, 0, 0x1000); #else var instructions = disassembler.DisassembleAll(code); diff --git a/Gee.External.Capstone/CapstoneDisassembler.cs b/Gee.External.Capstone/CapstoneDisassembler.cs index d3304bd..8a79b91 100644 --- a/Gee.External.Capstone/CapstoneDisassembler.cs +++ b/Gee.External.Capstone/CapstoneDisassembler.cs @@ -204,7 +204,7 @@ public abstract class CapstoneDisassembler /// The disassembler's mode. /// - protected CapstoneDisassembler(DisassembleArchitecture architecture, DisassembleMode mode) : base(architecture, mode) { } + protected CapstoneDisassembler(DisassembleArchitecture architecture, DisassembleMode mode) : base(architecture, mode) {} /// /// Disassemble Binary Code. @@ -275,19 +275,24 @@ public Instruction - /// Disassemble Binary Code incrementally. + /// Defer Disassemble Binary Code. /// /// /// A collection of bytes representing the binary code to disassemble. Should not be a null reference. /// + /// + /// An offset to start disassembling from. A 0 indicates disassembly should start at the first byte. + /// Should be less than the length of the collection of bytes to disassemble. + /// + /// + /// The address of the first instruction in the collection of bytes to disassemble. + /// /// - /// An IEnumerable deferred stream of dissembled instructions. + /// A deferred collection of dissembled instructions. /// - /// - /// Thrown if the binary code could not be disassembled. - /// - public IEnumerable> DisassembleStream(byte[] code, int offset, long startAddress) { - return new InstructionStream(this, code, offset, startAddress); + public IEnumerable> DisassembleStream(byte[] code, int offset, long startingAddress) { + var enumerable = new DeferredInstructionEnumerable(this, code, offset, startingAddress); + return enumerable; } /// @@ -319,97 +324,199 @@ public Instruction CreateInstruction(NativeInstruction nativeInstruction); /// - /// Provides an IEnumerable interface so that Capstone.NET can be used with - /// other .NET components, like LinQ, without having to eagerly disassemble - /// large areas of memory. + /// Deferred Instruction Enumerable. /// - private sealed class InstructionStream : IEnumerable> { + /// + /// Represents an enumerable that is used to support deferred enumeration of dissembled binary code. This + /// allows instruction-by-instruction disassembling of small ranges of code conveniently. This mode of + /// use is common with recursive disassemblers, which need to disassembly small chunks of code often. + /// + private sealed class DeferredInstructionEnumerable : IEnumerable> { + /// + /// Binary Code to Disassemble. + /// + private readonly byte[] _code; + + /// + /// Disassembler. + /// private readonly CapstoneDisassembler _disassembler; - private byte[] code; - private int offset; - private long address; - - public InstructionStream( - CapstoneDisassembler disassembler, - byte[] code, - int offset, - long address) - { + + /// + /// Offset. + /// + private readonly int _offset; + + /// + /// Starting Address. + /// + private readonly long _startingAddress; + + /// + /// Create a Deferred Instruction Enumerable. + /// + /// + /// The disassembler to use. Should not be a null reference. + /// + /// + /// A collection of bytes representing the binary code to disassemble. Should not be a null reference. + /// + /// + /// An offset to start disassembling from. A 0 indicates disassembly should start at the first byte. + /// Should be less than the length of the collection of bytes to disassemble. + /// + /// + /// The address of the first instruction in the collection of bytes to disassemble. + /// + public DeferredInstructionEnumerable(CapstoneDisassembler disassembler, byte[] code, int offset, long startingAddress) { this._disassembler = disassembler; - this.code = code; - this.offset = offset; - this.address = address; + this._code = code; + this._offset = offset; + this._startingAddress = startingAddress; } - - public IEnumerator> GetEnumerator() - { - return new InstructionEnumerator(_disassembler, code, offset, address); + + /// + /// Get Enumerator. + /// + /// + /// An enumerator. + /// + public IEnumerator> GetEnumerator() { + var enumerator = new DeferredInstructionEnumerator(this._disassembler, this._code, this._offset, this._startingAddress); + return enumerator; } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); + /// + /// Get Enumerator. + /// + /// + /// An enumerator. + /// + IEnumerator IEnumerable.GetEnumerator() { + var enumerator = this.GetEnumerator(); + return enumerator; } } /// - /// Enumerator that lazily disassembles a stream of instructions. + /// Deferred Instruction Enumerator. /// - private class InstructionEnumerator : - IEnumerator> { - private CapstoneDisassembler dasm; - private GCHandle pinnedCode; // Pinned array of bytes containing the area we wish to disassemble. - private int offset; // "cursor": the position within the code we're currently at. - private int codeSize; // the size of the code. - private Instruction current; - private ulong address; - - public InstructionEnumerator( - CapstoneDisassembler dasm, - byte[] code, - int offset, - long startAddress) { - this.dasm = dasm; - // Avoid copying the code to be disassembled, by pinning it instead. - this.pinnedCode = GCHandle.Alloc(code, GCHandleType.Pinned); - this.offset = offset; - this.codeSize = code.Length; - this.address = (ulong)startAddress; - } + /// + /// Represents an enumerator that is used to support deferred enumeration of dissembled binary code. This + /// allows instruction-by-instruction disassembling of small ranges of code conveniently. This mode of + /// use is common with recursive disassemblers, which need to disassembly small chunks of code often. + /// + private class DeferredInstructionEnumerator : IEnumerator> { + /// + /// Code Size. + /// + private readonly int _codeSize; + + /// + /// Current Address. + /// + private ulong _currentAddress; + + /// + /// Current Instruction. + /// + private Instruction _currentInstruction; + + /// + /// Current Offset. + /// + private int _currentOffset; + + /// + /// Disassembler. + /// + private readonly CapstoneDisassembler _disassembler; + + /// + /// Disposed Flag. + /// + private bool _disposed; /// - /// Finalize the enumerator. + /// Pinned Code. /// /// - /// The finalizer will be called at some non-specified time - /// if you forget to Dispose() this object. Avoid this by being - /// diligent with your resource management. + /// Represents a garbage collector handle to the collection of bytes representing the binary code to + /// disassemble. A "pinning" technique is used to pin the collection of bytes while enumerating + /// instead copying the data back and forth between managed and unmanaged memory. /// - ~InstructionEnumerator() { - Dispose(false); + private GCHandle _pinnedCode; + + /// + /// Created a Deferred Instruction Enumerator. + /// + /// + /// The disassembler to use. Should not be a null reference. + /// + /// + /// A collection of bytes representing the binary code to disassemble. Should not be a null reference. + /// + /// + /// An offset to start disassembling from. A 0 indicates disassembly should start at the first byte. + /// Should be less than the length of the collection of bytes to disassemble. + /// + /// + /// The address of the first instruction in the collection of bytes to disassemble. + /// + public DeferredInstructionEnumerator(CapstoneDisassembler disassembler, byte[] code, int offset, long startingAddress) { + this._disassembler = disassembler; + this._pinnedCode = GCHandle.Alloc(code, GCHandleType.Pinned); + this._currentOffset = offset; + this._currentAddress = (ulong) startingAddress; + + this._codeSize = code.Length; + this._disposed = false; + } + + /// + /// Destroy Deferred Instruction Enumerator. + /// + ~DeferredInstructionEnumerator() { + this.Dispose(false); } /// /// Gets the current instruction in the instruction stream. /// /// - /// Thrown if the caller attempts to read this property before - /// calling the MoveNext() method. + /// Thrown if an initial call to DeferredInstructionEnumerator.MoveNext() was not made. + /// + /// + /// Thrown if the enumerator is disposed. /// public Instruction Current { get { - if (current == null) + this.CheckDisposed(); + if (_currentInstruction == null) { throw new InvalidOperationException(); - return current; + } + + return this._currentInstruction; } } + /// + /// Get Current Instruction. + /// + /// + /// Thrown if an initial call to DeferredInstructionEnumerator.MoveNext() was not made. + /// + /// + /// Thrown if the enumerator is disposed. + /// object IEnumerator.Current { - get { return Current; } + get { + return this.Current; + } } /// - /// Dispose() method is called automatically by foreach + /// Destroy Deferred Instruction Enumerator. /// public void Dispose() { Dispose(true); @@ -417,45 +524,78 @@ public void Dispose() { } /// - /// Disposes of any unmanaged/unsafe resources. + /// Get Next Instruction. /// - /// - private void Dispose(bool disposing) { - if (pinnedCode.IsAllocated) - pinnedCode.Free(); - } - - /// - /// Retrieve the next instruction using the native Capstone disassembler. - /// - /// + /// + /// A boolean true if an instruction is returned. A boolean false otherwise. + /// + /// + /// Thrown if the enumerator is disposed. + /// public bool MoveNext() { - var pCount = (IntPtr)1; - var pCode = this.pinnedCode.AddrOfPinnedObject() + offset; + this.CheckDisposed(); + + var pCode = this._pinnedCode.AddrOfPinnedObject() + this._currentOffset; + var pCount = (IntPtr) 1; var pInstructions = IntPtr.Zero; - var pSize = (IntPtr)codeSize - offset; - var uStartingAddress = (ulong)address; + var pSize = (IntPtr) this._codeSize - this._currentOffset; - var pResultCode = CapstoneImport.Disassemble(dasm.Handle.DangerousGetHandle(), pCode, pSize, uStartingAddress, pCode, ref pInstructions); + // Disassemble Binary Code. + // + // ... + var pResultCode = CapstoneImport.Disassemble(_disassembler.Handle.DangerousGetHandle(), pCode, pSize, this._currentAddress, pCount, ref pInstructions); - var iResultCode = (int)pResultCode; - var instructions = MarshalExtension.PtrToStructure(pInstructions, iResultCode); - if (instructions == null || instructions.Length == 0) + var iResultCode = (int) pResultCode; + var nativeInstructions = MarshalExtension.PtrToStructure(pInstructions, iResultCode); + if (nativeInstructions == null || nativeInstructions.Length == 0) { return false; + } + + var instruction = nativeInstructions[0]; + this._currentInstruction = this._disassembler.CreateInstruction(instruction); + this._currentAddress += (ulong) this._currentInstruction.Bytes.Length; + this._currentOffset += this._currentInstruction.Bytes.Length; - // Update the state of the IEnumerator. - this.current = dasm.CreateInstruction(instructions[0]); - this.address += (ulong) current.Bytes.Length; - this.offset += current.Bytes.Length; return true; } /// - /// The Reset method is not supported; it is rarely used in practice. + /// Reset Enumerator. /// + /// + /// Thrown always. + /// public void Reset() { throw new NotSupportedException(); } + + /// + /// Destroy Deferred Instruction Enumerator. + /// + /// + /// A boolean true if the enumerator is being disposed from application code. A boolean false otherwise. + /// + private void Dispose(bool disposing) { + if (!this._disposed) { + if (this._pinnedCode.IsAllocated) { + this._pinnedCode.Free(); + } + + this._disposed = true; + } + } + + /// + /// Check if Enumerator is Disposed. + /// + /// + /// Thrown if the enumerator is disposed. + /// + private void CheckDisposed() { + if (this._disposed) { + throw new ObjectDisposedException("DeferredInstructionEnumerator"); + } + } } } } \ No newline at end of file diff --git a/Gee.External.Capstone/Gee.External.Capstone.csproj b/Gee.External.Capstone/Gee.External.Capstone.csproj index 5cda849..25afc5c 100644 --- a/Gee.External.Capstone/Gee.External.Capstone.csproj +++ b/Gee.External.Capstone/Gee.External.Capstone.csproj @@ -30,6 +30,7 @@ x86 prompt MinimumRecommendedRules.ruleset + true diff --git a/Gee.External.Capstone/NativeInstructionCollection.cs b/Gee.External.Capstone/NativeInstructionCollection.cs index b07de7b..c5ae25c 100644 --- a/Gee.External.Capstone/NativeInstructionCollection.cs +++ b/Gee.External.Capstone/NativeInstructionCollection.cs @@ -6,6 +6,7 @@ namespace Gee.External.Capstone { /// /// Native Instruction Collection. /// + [Obsolete("Deprecated.")] internal sealed class NativeInstructionCollection : IEnumerable { /// /// Native Instructions. diff --git a/Gee.External.Capstone/NativeInstructionCollectionEnumerator.cs b/Gee.External.Capstone/NativeInstructionCollectionEnumerator.cs index 6bac8e0..4ace8e4 100644 --- a/Gee.External.Capstone/NativeInstructionCollectionEnumerator.cs +++ b/Gee.External.Capstone/NativeInstructionCollectionEnumerator.cs @@ -6,6 +6,7 @@ namespace Gee.External.Capstone { /// /// Native Instruction Collection Enumerator. /// + [Obsolete("Deprecated.")] internal sealed class NativeInstructionCollectionEnumerator : IEnumerator { /// /// Current Native Instruction's Index.