diff --git a/Gee.External.Capstone/CapstoneDisassembler.cs b/Gee.External.Capstone/CapstoneDisassembler.cs index b905ba7..05a7274 100644 --- a/Gee.External.Capstone/CapstoneDisassembler.cs +++ b/Gee.External.Capstone/CapstoneDisassembler.cs @@ -767,13 +767,10 @@ NativeDisassembleMode CreateNativeDisassembleMode(CapstoneDisassembler /// An array of disassembled instructions. /// - /// - /// Thrown if the binary code array is a null reference. - /// /// /// Thrown if the disassembler is disposed. /// - public TInstruction[] Disassemble(byte[] binaryCode) { + public TInstruction[] Disassemble(ReadOnlySpan binaryCode) { // ... // // Throws an exception if the operation fails. @@ -793,13 +790,10 @@ public TInstruction[] Disassemble(byte[] binaryCode) { /// /// An array of disassembled instructions. /// - /// - /// Thrown if the binary code array is a null reference. - /// /// /// Thrown if the disassembler is disposed. /// - public TInstruction[] Disassemble(byte[] binaryCode, long startingAddress) { + public TInstruction[] Disassemble(ReadOnlySpan binaryCode, long startingAddress) { // ... // // Throws an exception if the operation fails. @@ -822,13 +816,10 @@ public TInstruction[] Disassemble(byte[] binaryCode, long startingAddress) { /// /// An array of disassembled instructions. /// - /// - /// Thrown if the binary code array is a null reference. - /// /// /// Thrown if the disassembler is disposed. /// - public TInstruction[] Disassemble(byte[] binaryCode, long startingAddress, int count) { + public TInstruction[] Disassemble(ReadOnlySpan binaryCode, long startingAddress, int count) { // ... // // Throws an exception if the operation fails. @@ -954,13 +945,10 @@ public string GetRegisterName(TRegisterId registerId) { /// /// A deferred collection of disassembled instructions. /// - /// - /// Thrown if the binary code array is a null reference. - /// /// /// Thrown if the disassembler is disposed. /// - public IEnumerable Iterate(byte[] binaryCode) { + public IEnumerable Iterate(ReadOnlySpan binaryCode) { // ... // // Throws an exception if the operation fails. @@ -979,15 +967,10 @@ public IEnumerable Iterate(byte[] binaryCode) { /// /// A deferred collection of disassembled instructions. /// - /// - /// Thrown if the binary code array is a null reference. - /// /// /// Thrown if the disassembler is disposed. /// - public IEnumerable Iterate(byte[] binaryCode, long startingAddress) { - CapstoneDisassembler.ThrowIfValueIsNullReference(nameof(binaryCode), binaryCode); - + public IEnumerable Iterate(ReadOnlySpan binaryCode, long startingAddress) { var binaryCodeOffset = 0; // ... @@ -1021,7 +1004,7 @@ public IEnumerable Iterate(byte[] binaryCode, long startingAddress // // To make this work though, we MUST define a local variable for the delegate! if (this._skipDataCallback != null) { - callback = OnNativeSkipDataCallback; + callback = CreateCallback(binaryCode.ToArray()); } // ... @@ -1067,24 +1050,28 @@ public IEnumerable Iterate(byte[] binaryCode, long startingAddress } } - // - // Native Skip Data Mode Callback. - // - IntPtr OnNativeSkipDataCallback(IntPtr cPBinaryCode, IntPtr cBinaryCodeSize, IntPtr cDataOffset, IntPtr pState) { - // ... - // - // Normally, a closure enclosing over a variable modified from a loop, such as this method, is a - // problem because the value of the variable is resolved at the time the closure is invoked and not - // when the variable is captured. This can lead to unexpected behavior if the closure is invoked - // outside the loop since the value of the captured variable will always be resolved to the last value - // it was set to inside the loop. - // - // However, because this closure will always be invoked from inside a disassemble loop, and never from - // outside of one, the variable value resolution behavior is exactly what we are looking for. We want - // the Capstone API to invoke this callback with an updated value for the captured variable every - // time! - var cBytesToSkip = this.SkipDataCallback(binaryCode, binaryCodeOffset); - return new IntPtr(cBytesToSkip); + NativeCapstone.SkipDataCallback CreateCallback(byte[] binaryCode) { + return OnNativeSkipDataCallback; + + // + // Native Skip Data Mode Callback. + // + IntPtr OnNativeSkipDataCallback(IntPtr cPBinaryCode, IntPtr cBinaryCodeSize, IntPtr cDataOffset, IntPtr pState) { + // ... + // + // Normally, a closure enclosing over a variable modified from a loop, such as this method, is a + // problem because the value of the variable is resolved at the time the closure is invoked and not + // when the variable is captured. This can lead to unexpected behavior if the closure is invoked + // outside the loop since the value of the captured variable will always be resolved to the last value + // it was set to inside the loop. + // + // However, because this closure will always be invoked from inside a disassemble loop, and never from + // outside of one, the variable value resolution behavior is exactly what we are looking for. We want + // the Capstone API to invoke this callback with an updated value for the captured variable every + // time! + var cBytesToSkip = this.SkipDataCallback(binaryCode, binaryCodeOffset); + return new IntPtr(cBytesToSkip); + } } } diff --git a/Gee.External.Capstone/Gee.External.Capstone.csproj b/Gee.External.Capstone/Gee.External.Capstone.csproj index 23fdb4c..4ee3bea 100644 --- a/Gee.External.Capstone/Gee.External.Capstone.csproj +++ b/Gee.External.Capstone/Gee.External.Capstone.csproj @@ -27,4 +27,8 @@ + + + + \ No newline at end of file diff --git a/Gee.External.Capstone/NativeCapstone.cs b/Gee.External.Capstone/NativeCapstone.cs index c1bae9e..3aaf449 100644 --- a/Gee.External.Capstone/NativeCapstone.cs +++ b/Gee.External.Capstone/NativeCapstone.cs @@ -472,14 +472,13 @@ internal static Version GetVersion() { /// /// Thrown if the disassembler handle is disposed, or if the instruction handle is disposed. /// - internal static bool Iterate(NativeDisassemblerHandle hDisassembler, byte[] binaryCode, ref int binaryCodeOffset, ref long address, NativeInstructionHandle hInstruction) { - var hBinaryCode = GCHandle.Alloc(binaryCode, GCHandleType.Pinned); - try { + internal static unsafe bool Iterate(NativeDisassemblerHandle hDisassembler, ReadOnlySpan binaryCode, ref int binaryCodeOffset, ref long address, NativeInstructionHandle hInstruction) { + fixed (byte* fixedPointer = binaryCode) { // ... // // First, we increment the pointer to the binary code buffer to the point to the address of the // instruction we want to disassemble. - var pBinaryCode = hBinaryCode.AddrOfPinnedObject() + binaryCodeOffset; + var pBinaryCode = (IntPtr)fixedPointer + binaryCodeOffset; // ... // @@ -508,11 +507,6 @@ internal static bool Iterate(NativeDisassemblerHandle hDisassembler, byte[] bina return isDisassembled; } - finally { - if (hBinaryCode.IsAllocated) { - hBinaryCode.Free(); - } - } } ///