From 2123ed2c5d89c593a8f8d7949e2f867cfc0e29d2 Mon Sep 17 00:00:00 2001 From: bird_egop Date: Tue, 15 Apr 2025 22:20:46 +0300 Subject: [PATCH] add tons of tests --- .../X86/Handlers/Sub/SubAxImm16Handler.cs | 4 +- X86Disassembler/X86/InstructionType.cs | 46 ++++- X86DisassemblerTests/CsvJsonConverter.cs | 4 + .../RawFromFileDisassemblyTests.cs | 187 +++++++----------- X86DisassemblerTests/TestData/adc_tests.csv | 25 +++ X86DisassemblerTests/TestData/add_tests.csv | 26 +++ X86DisassemblerTests/TestData/and_tests.csv | 25 +++ X86DisassemblerTests/TestData/bit_tests.csv | 59 ++++++ X86DisassemblerTests/TestData/call_tests.csv | 68 +++++++ X86DisassemblerTests/TestData/cmp_tests.csv | 25 +++ X86DisassemblerTests/TestData/div_tests.csv | 24 +++ X86DisassemblerTests/TestData/flag_tests.csv | 30 +++ .../TestData/fnstsw_tests.csv | 15 ++ X86DisassemblerTests/TestData/fpu_tests.csv | 109 ++++++++++ .../TestData/group3_instruction_tests.csv | 60 ++++++ X86DisassemblerTests/TestData/idiv_tests.csv | 24 +++ X86DisassemblerTests/TestData/imul_tests.csv | 41 ++++ X86DisassemblerTests/TestData/jcc_tests.csv | 39 ++++ X86DisassemblerTests/TestData/jmp_tests.csv | 58 ++++++ X86DisassemblerTests/TestData/lea_tests.csv | 64 ++++++ X86DisassemblerTests/TestData/misc_tests.csv | 52 +++++ X86DisassemblerTests/TestData/mov_tests.csv | 91 +++++++++ X86DisassemblerTests/TestData/mul_tests.csv | 24 +++ X86DisassemblerTests/TestData/neg_tests.csv | 24 +++ X86DisassemblerTests/TestData/nop_tests.csv | 18 +- X86DisassemblerTests/TestData/not_tests.csv | 24 +++ X86DisassemblerTests/TestData/or_tests.csv | 25 +++ .../TestData/popreg_tests.csv | 20 +- X86DisassemblerTests/TestData/poprm_tests.csv | 40 ++++ .../TestData/pushimm_tests.csv | 20 +- .../TestData/pushreg_tests.csv | 20 +- .../TestData/pushrm_tests.csv | 40 ++++ X86DisassemblerTests/TestData/rcl_tests.csv | 32 +++ X86DisassemblerTests/TestData/rcr_tests.csv | 32 +++ X86DisassemblerTests/TestData/ret_tests.csv | 23 +++ X86DisassemblerTests/TestData/rol_tests.csv | 32 +++ X86DisassemblerTests/TestData/ror_tests.csv | 32 +++ X86DisassemblerTests/TestData/sar_tests.csv | 32 +++ X86DisassemblerTests/TestData/sbb_tests.csv | 25 +++ .../TestData/segment_override_tests.csv | 66 ++++++- X86DisassemblerTests/TestData/shl_tests.csv | 32 +++ X86DisassemblerTests/TestData/shr_tests.csv | 32 +++ X86DisassemblerTests/TestData/stack_tests.csv | 24 +++ .../TestData/string_tests.csv | 52 +++++ X86DisassemblerTests/TestData/sub_tests.csv | 82 +++++--- X86DisassemblerTests/TestData/test_tests.csv | 24 +++ X86DisassemblerTests/TestData/xchg_tests.csv | 42 +++- X86DisassemblerTests/TestData/xor_tests.csv | 88 ++++----- X86DisassemblerTests/TestDataProvider.cs | 98 +++++++++ X86DisassemblerTests/TestFromFileEntry.cs | 57 ++---- .../X86DisassemblerTests.csproj | 102 ++++++---- 51 files changed, 1927 insertions(+), 311 deletions(-) create mode 100644 X86DisassemblerTests/TestData/adc_tests.csv create mode 100644 X86DisassemblerTests/TestData/add_tests.csv create mode 100644 X86DisassemblerTests/TestData/and_tests.csv create mode 100644 X86DisassemblerTests/TestData/bit_tests.csv create mode 100644 X86DisassemblerTests/TestData/call_tests.csv create mode 100644 X86DisassemblerTests/TestData/cmp_tests.csv create mode 100644 X86DisassemblerTests/TestData/div_tests.csv create mode 100644 X86DisassemblerTests/TestData/flag_tests.csv create mode 100644 X86DisassemblerTests/TestData/fnstsw_tests.csv create mode 100644 X86DisassemblerTests/TestData/fpu_tests.csv create mode 100644 X86DisassemblerTests/TestData/group3_instruction_tests.csv create mode 100644 X86DisassemblerTests/TestData/idiv_tests.csv create mode 100644 X86DisassemblerTests/TestData/imul_tests.csv create mode 100644 X86DisassemblerTests/TestData/jcc_tests.csv create mode 100644 X86DisassemblerTests/TestData/jmp_tests.csv create mode 100644 X86DisassemblerTests/TestData/lea_tests.csv create mode 100644 X86DisassemblerTests/TestData/misc_tests.csv create mode 100644 X86DisassemblerTests/TestData/mov_tests.csv create mode 100644 X86DisassemblerTests/TestData/mul_tests.csv create mode 100644 X86DisassemblerTests/TestData/neg_tests.csv create mode 100644 X86DisassemblerTests/TestData/not_tests.csv create mode 100644 X86DisassemblerTests/TestData/or_tests.csv create mode 100644 X86DisassemblerTests/TestData/poprm_tests.csv create mode 100644 X86DisassemblerTests/TestData/pushrm_tests.csv create mode 100644 X86DisassemblerTests/TestData/rcl_tests.csv create mode 100644 X86DisassemblerTests/TestData/rcr_tests.csv create mode 100644 X86DisassemblerTests/TestData/ret_tests.csv create mode 100644 X86DisassemblerTests/TestData/rol_tests.csv create mode 100644 X86DisassemblerTests/TestData/ror_tests.csv create mode 100644 X86DisassemblerTests/TestData/sar_tests.csv create mode 100644 X86DisassemblerTests/TestData/sbb_tests.csv create mode 100644 X86DisassemblerTests/TestData/shl_tests.csv create mode 100644 X86DisassemblerTests/TestData/shr_tests.csv create mode 100644 X86DisassemblerTests/TestData/stack_tests.csv create mode 100644 X86DisassemblerTests/TestData/string_tests.csv create mode 100644 X86DisassemblerTests/TestData/test_tests.csv create mode 100644 X86DisassemblerTests/TestDataProvider.cs diff --git a/X86Disassembler/X86/Handlers/Sub/SubAxImm16Handler.cs b/X86Disassembler/X86/Handlers/Sub/SubAxImm16Handler.cs index b147188..57c3b67 100644 --- a/X86Disassembler/X86/Handlers/Sub/SubAxImm16Handler.cs +++ b/X86Disassembler/X86/Handlers/Sub/SubAxImm16Handler.cs @@ -47,9 +47,7 @@ public class SubAxImm16Handler : InstructionHandler var immediate = Decoder.ReadUInt16(); // Create the destination register operand (AX) - // Note: Even though we're dealing with 16-bit operations (AX), - // the tests expect 32-bit register names (EAX) in the output - var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32); + var destinationOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16); // Create the source immediate operand var sourceOperand = OperandFactory.CreateImmediateOperand(immediate, 16); diff --git a/X86Disassembler/X86/InstructionType.cs b/X86Disassembler/X86/InstructionType.cs index daacab2..dc7943d 100644 --- a/X86Disassembler/X86/InstructionType.cs +++ b/X86Disassembler/X86/InstructionType.cs @@ -10,6 +10,7 @@ public enum InstructionType Push, Pop, Xchg, + Lea, // Load Effective Address // Arithmetic Add, @@ -46,7 +47,7 @@ public enum InstructionType Bsr, // Bit scan reverse // Control flow - Jmp, + Jmp, // Jump unconditionally Je, // Jump if equal Jne, // Jump if not equal Jg, // Jump if greater @@ -63,14 +64,18 @@ public enum InstructionType Jno, // Jump if not overflow Js, // Jump if sign Jns, // Jump if not sign + Jp, // Jump if parity (even) + Jnp, // Jump if not parity (odd) Jcxz, // Jump if CX zero Jecxz, // Jump if ECX zero Loop, // Loop Loope, // Loop if equal Loopne, // Loop if not equal - Call, - Ret, + Call, // Call procedure + Ret, // Near return from procedure + Retf, // Far return from procedure Int, // Interrupt + Int3, // Breakpoint interrupt Into, // Interrupt if overflow Iret, // Interrupt return @@ -122,6 +127,9 @@ public enum InstructionType RepLodsB, // REP LODSB RepLodsW, // REP LODSW RepLodsD, // REP LODSD + RepneCmpsB, // REPNE CMPSB + RepneCmpsD, // REPNE CMPSD + RepneCmpsW, // REPNE CMPSW // Floating point Fld, // Load floating point value @@ -158,20 +166,33 @@ public enum InstructionType Fisttp, // Store integer with truncation and pop Fbld, // Load BCD Fbstp, // Store BCD and pop - Fnstsw, // Store FPU status word + Fnstsw, // Store FPU status word without checking for pending unmasked exceptions + Fstsw, // Store FPU status word Fnstcw, // Store FPU control word Fldcw, // Load FPU control word + Fxam, // Examine floating point value + Finit, // Initialize FPU (with FWAIT prefix) + Fninit, // Initialize FPU without checking for pending unmasked exceptions Fclex, // Clear floating-point exceptions - Finit, // Initialize floating-point unit Fldenv, // Load FPU environment Fnstenv, // Store FPU environment Frstor, // Restore FPU state + + // Flag control instructions + Stc, // Set Carry Flag + Clc, // Clear Carry Flag + Cmc, // Complement Carry Flag + Std, // Set Direction Flag + Cld, // Clear Direction Flag + Sti, // Set Interrupt Flag + Cli, // Clear Interrupt Flag + Sahf, // Store AH into Flags + Lahf, // Load Flags into AH Fnsave, // Save FPU state Fxch, // Exchange floating point registers Fchs, // Change sign of floating point value Fabs, // Absolute value of floating point Ftst, // Test floating point - Fxam, // Examine floating point F2xm1, // 2^x - 1 Fyl2x, // y * log2(x) Fptan, // Partial tangent @@ -205,9 +226,20 @@ public enum InstructionType Hlt, // Halt Cpuid, // CPU identification Rdtsc, // Read time-stamp counter + Wait, // Wait for FPU + Lock, // Lock prefix + In, // Input from port + Out, // Output to port + + // Stack-related instructions + Pushad, // Push all general-purpose registers + Popad, // Pop all general-purpose registers + Pushfd, // Push EFLAGS register onto the stack + Popfd, // Pop stack into EFLAGS register + Enter, // Make stack frame for procedure parameters + Leave, // High level procedure exit // Other - Lea, // Load effective address Nop, // No operation Cdq, // Convert doubleword to quadword Cwde, // Convert word to doubleword diff --git a/X86DisassemblerTests/CsvJsonConverter.cs b/X86DisassemblerTests/CsvJsonConverter.cs index 0db826a..4b5e5b9 100644 --- a/X86DisassemblerTests/CsvJsonConverter.cs +++ b/X86DisassemblerTests/CsvJsonConverter.cs @@ -8,6 +8,10 @@ namespace X86DisassemblerTests; // ReSharper disable once ClassNeverInstantiated.Global public sealed class CsvJsonConverter : DefaultTypeConverter { + private static JsonSerializerOptions _options = new JsonSerializerOptions() + { + }; + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) { if (text is null) diff --git a/X86DisassemblerTests/RawFromFileDisassemblyTests.cs b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs index c740482..c8e02e1 100644 --- a/X86DisassemblerTests/RawFromFileDisassemblyTests.cs +++ b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs @@ -1,143 +1,99 @@ -using System.Globalization; -using System.Reflection; -using CsvHelper; -using CsvHelper.Configuration; using X86Disassembler.X86; -using X86Disassembler.X86.Operands; using Xunit.Abstractions; namespace X86DisassemblerTests; +/// +/// Tests for disassembling raw bytes from CSV test files +/// public class RawFromFileDisassemblyTests(ITestOutputHelper output) { [Theory] - [InlineData("pushreg_tests.csv")] - [InlineData("popreg_tests.csv")] - [InlineData("pushimm_tests.csv")] - [InlineData("nop_tests.csv")] - [InlineData("xchg_tests.csv")] - [InlineData("sub_tests.csv")] - [InlineData("xor_tests.csv")] - [InlineData("segment_override_tests.csv")] - public void RunTests(string file) + [ClassData(typeof(TestDataProvider))] + public void RunTests(string f, int idx, TestFromFileEntry test) { - // Load the CSV test file from embedded resources - using var stream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"X86DisassemblerTests.TestData.{file}"); + // Convert hex string to byte array + byte[] code = HexStringToByteArray(test.RawBytes); - if (stream == null) + // Create a disassembler with the code + Disassembler disassembler = new Disassembler(code, 0x1000); + + // Disassemble the code + var disassembledInstructions = disassembler.Disassemble(); + + // Verify the number of instructions + if (test.Instructions.Count != disassembledInstructions.Count) { - throw new InvalidOperationException($"Could not find {file} embedded resource"); + AssertFailWithReason( + idx, + f, + test, + disassembledInstructions, + "Instruction count mismatch" + ); } - // Configure CSV reader with semicolon delimiter - var config = new CsvConfiguration(CultureInfo.InvariantCulture) + // Verify each instruction + for (int i = 0; i < test.Instructions.Count; i++) { - HasHeaderRecord = true, - Delimiter = ";", - BadDataFound = null, // Ignore bad data - AllowComments = true, // Enable comments in CSV files - Comment = '#', // Use # as the comment character - IgnoreBlankLines = true // Skip empty lines - }; + var expected = test.Instructions[i]; + var actual = disassembledInstructions[i]; - using var streamReader = new StreamReader(stream); - using var csvReader = new CsvReader(streamReader, config); - - // Register class map for TestFromFileEntry - csvReader.Context.RegisterClassMap(); - - // Read all records from CSV - var tests = csvReader.GetRecords() - .ToList(); - - // Run tests for each instruction - for (var index = 0; index < tests.Count; index++) - { - var test = tests[index]; - - // Convert hex string to byte array - byte[] code = HexStringToByteArray(test.RawBytes); - - // Create a disassembler with the code - Disassembler disassembler = new Disassembler(code, 0x1000); - - // Disassemble the code - var disassembledInstructions = disassembler.Disassemble(); - - // Verify the number of instructions - if (test.Instructions.Count != disassembledInstructions.Count) + // Compare instruction type instead of mnemonic + if (expected.Type != actual.Type) { AssertFailWithReason( - index, - file, + idx, + f, test, disassembledInstructions, - "Instruction count mismatch" + $"Type mismatch: Expected {expected.Type}, got {actual.Type}" ); } - // Verify each instruction - for (int i = 0; i < test.Instructions.Count; i++) + // Compare operands + if (!CompareOperands(expected.Operands, actual.StructuredOperands)) { - var expected = test.Instructions[i]; - var actual = disassembledInstructions[i]; - - // Compare instruction type instead of mnemonic - if (expected.Type != actual.Type) - { - AssertFailWithReason( - index, - file, - test, - disassembledInstructions, - $"Type mismatch: Expected {expected.Type}, got {actual.Type}" - ); - } - - // For operands, we need to do a string comparison since the CSV contains string operands - // and we now have structured operands in the actual instruction - string actualOperandsString = string.Join(", ", actual.StructuredOperands); - if (!CompareOperands(expected.Operands, actualOperandsString)) - { - AssertFailWithReason( - index, - file, - test, - disassembledInstructions, - $"Operands mismatch: Expected '{expected.Operands}', got '{actualOperandsString}'" - ); - } + AssertFailWithReason( + idx, + f, + test, + disassembledInstructions, + $"Operands mismatch: \n" + + $"Expected: {string.Join(", ", expected.Operands)}.\n" + + $"Actual: {string.Join(", ", actual.StructuredOperands.Select(x => $"{x.GetType().Name}({x})"))}" + ); } } } - // Compare operands with some flexibility since the string representation might be slightly different - private bool CompareOperands(string expected, string actual) + /// + /// Compare operands with some flexibility since the string representation might be slightly different + /// + private bool CompareOperands(string[] expectedOperands, List actualOperands) { - // Normalize strings for comparison - expected = NormalizeOperandString(expected); - actual = NormalizeOperandString(actual); - - return expected == actual; - } - - // Normalize operand strings to handle slight formatting differences - private string NormalizeOperandString(string operands) - { - if (string.IsNullOrEmpty(operands)) - return string.Empty; - - // Remove all spaces - operands = operands.Replace(" ", ""); - - // Convert to lowercase - operands = operands.ToLowerInvariant(); - - // Normalize hex values (remove 0x prefix if present) - operands = operands.Replace("0x", ""); - - return operands; + // Check if the number of operands matches + if (expectedOperands.Length != actualOperands.Count) + { + return false; + } + + // Initialize result to true and set to false if any operand doesn't match + bool result = true; + + // Compare each operand + for (var i = 0; i < expectedOperands.Length; i++) + { + var expected = expectedOperands[i]; + var actual = actualOperands[i]; + + if (expected == actual.ToString()) continue; + + result = false; + break; + } + + return result; } private void AssertFailWithReason(int index, string file, TestFromFileEntry test, List disassembledInstructions, string reason) @@ -147,16 +103,19 @@ public class RawFromFileDisassemblyTests(ITestOutputHelper output) output.WriteLine("Expected instructions:"); foreach (var instruction in test.Instructions) { - output.WriteLine($" {instruction.Mnemonic} {instruction.Operands}"); + output.WriteLine($" {instruction.Type:G} {string.Join(",", instruction.Operands)}"); } output.WriteLine("Actual instructions:"); foreach (var instruction in disassembledInstructions) { output.WriteLine($" {instruction.Type} {string.Join(", ", instruction.StructuredOperands)}"); } - Assert.True(false, reason); + Assert.Fail(reason); } + /// + /// Converts a hexadecimal string to a byte array + /// private static byte[] HexStringToByteArray(string hex) { // Remove any spaces or other formatting characters diff --git a/X86DisassemblerTests/TestData/adc_tests.csv b/X86DisassemblerTests/TestData/adc_tests.csv new file mode 100644 index 0000000..c6572b5 --- /dev/null +++ b/X86DisassemblerTests/TestData/adc_tests.csv @@ -0,0 +1,25 @@ +# ADC instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# ADC r/m8, imm8 (opcode 80 /2) +80D042;[{ "Type": "Adc", "Operands": ["al", "0x42"] }] + +# ADC r/m32, imm32 (opcode 81 /2) +81D078563412;[{ "Type": "Adc", "Operands": ["eax", "0x12345678"] }] + +# ADC r/m32, imm8 (opcode 83 /2) +83D042;[{ "Type": "Adc", "Operands": ["eax", "0x42"] }] + +# ADC with memory operands +8114251000000078563412;[{ "Type": "Adc", "Operands": ["dword ptr [0x10]", "0x12345678"] }] + +# ADC r/m32, r32 (opcode 11) +11D8;[{ "Type": "Adc", "Operands": ["eax", "ebx"] }] +11CA;[{ "Type": "Adc", "Operands": ["edx", "ecx"] }] +114B10;[{ "Type": "Adc", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# ADC r32, r/m32 (opcode 13) +13D8;[{ "Type": "Adc", "Operands": ["ebx", "eax"] }] +13CA;[{ "Type": "Adc", "Operands": ["ecx", "edx"] }] +134B10;[{ "Type": "Adc", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/add_tests.csv b/X86DisassemblerTests/TestData/add_tests.csv new file mode 100644 index 0000000..e39f447 --- /dev/null +++ b/X86DisassemblerTests/TestData/add_tests.csv @@ -0,0 +1,26 @@ +# ADD instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# ADD r/m8, imm8 (opcode 80 /0) +80C042;[{ "Type": "Add", "Operands": ["al", "0x42"] }] + +# ADD r/m32, imm32 (opcode 81 /0) +81C078563412;[{ "Type": "Add", "Operands": ["eax", "0x12345678"] }] + +# ADD r/m32, imm8 (opcode 83 /0) with sign extension +83C042;[{ "Type": "Add", "Operands": ["eax", "0x42"] }] +83C0FF;[{ "Type": "Add", "Operands": ["eax", "0xFFFFFFFF"] }] + +# ADD with memory operands +8104251000000078563412;[{ "Type": "Add", "Operands": ["dword ptr [0x10]", "0x12345678"] }] + +# ADD r/m32, r32 (opcode 01) +01D8;[{ "Type": "Add", "Operands": ["eax", "ebx"] }] +01CA;[{ "Type": "Add", "Operands": ["edx", "ecx"] }] +014B10;[{ "Type": "Add", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# ADD r32, r/m32 (opcode 03) +03D8;[{ "Type": "Add", "Operands": ["ebx", "eax"] }] +03CA;[{ "Type": "Add", "Operands": ["ecx", "edx"] }] +034B10;[{ "Type": "Add", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/and_tests.csv b/X86DisassemblerTests/TestData/and_tests.csv new file mode 100644 index 0000000..7aede0e --- /dev/null +++ b/X86DisassemblerTests/TestData/and_tests.csv @@ -0,0 +1,25 @@ +# AND instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# AND r/m8, imm8 (opcode 80 /4) +80E042;[{ "Type": "And", "Operands": ["al", "0x42"] }] + +# AND r/m32, imm32 (opcode 81 /4) +81E078563412;[{ "Type": "And", "Operands": ["eax", "0x12345678"] }] + +# AND r/m32, imm8 (opcode 83 /4) +83E042;[{ "Type": "And", "Operands": ["eax", "0x42"] }] + +# AND with memory operands +8124251000000078563412;[{ "Type": "And", "Operands": ["dword ptr [0x10]", "0x12345678"] }] + +# AND r/m32, r32 (opcode 21) +21D8;[{ "Type": "And", "Operands": ["eax", "ebx"] }] +21CA;[{ "Type": "And", "Operands": ["edx", "ecx"] }] +214B10;[{ "Type": "And", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# AND r32, r/m32 (opcode 23) +23D8;[{ "Type": "And", "Operands": ["ebx", "eax"] }] +23CA;[{ "Type": "And", "Operands": ["ecx", "edx"] }] +234B10;[{ "Type": "And", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/bit_tests.csv b/X86DisassemblerTests/TestData/bit_tests.csv new file mode 100644 index 0000000..4b7a7fe --- /dev/null +++ b/X86DisassemblerTests/TestData/bit_tests.csv @@ -0,0 +1,59 @@ +# Bit manipulation instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# BT - Bit Test +0FA3C1;[{ "Type": "Bt", "Operands": ["ecx", "eax"] }] +0FA3D9;[{ "Type": "Bt", "Operands": ["ecx", "ebx"] }] +0FA3CA;[{ "Type": "Bt", "Operands": ["edx", "ecx"] }] +0FA30425;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "eax"] }] +0FA30C25;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "ecx"] }] +0FA31425;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "edx"] }] +0FBA2005;[{ "Type": "Bt", "Operands": ["dword ptr [eax]", "0x05"] }] +0FBA2505;[{ "Type": "Bt", "Operands": ["dword ptr [ebp]", "0x05"] }] + +# BTS - Bit Test and Set +0FABC1;[{ "Type": "Bts", "Operands": ["ecx", "eax"] }] +0FABD9;[{ "Type": "Bts", "Operands": ["ecx", "ebx"] }] +0FABCA;[{ "Type": "Bts", "Operands": ["edx", "ecx"] }] +0FAB0425;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "eax"] }] +0FAB0C25;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "ecx"] }] +0FAB1425;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "edx"] }] +0FBA2805;[{ "Type": "Bts", "Operands": ["dword ptr [eax]", "0x05"] }] +0FBA2D05;[{ "Type": "Bts", "Operands": ["dword ptr [ebp]", "0x05"] }] + +# BTR - Bit Test and Reset +0FB3C1;[{ "Type": "Btr", "Operands": ["ecx", "eax"] }] +0FB3D9;[{ "Type": "Btr", "Operands": ["ecx", "ebx"] }] +0FB3CA;[{ "Type": "Btr", "Operands": ["edx", "ecx"] }] +0FB30425;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "eax"] }] +0FB30C25;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "ecx"] }] +0FB31425;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "edx"] }] +0FBA3005;[{ "Type": "Btr", "Operands": ["dword ptr [eax]", "0x05"] }] +0FBA3505;[{ "Type": "Btr", "Operands": ["dword ptr [ebp]", "0x05"] }] + +# BTC - Bit Test and Complement +0FBBC1;[{ "Type": "Btc", "Operands": ["ecx", "eax"] }] +0FBBD9;[{ "Type": "Btc", "Operands": ["ecx", "ebx"] }] +0FBBCA;[{ "Type": "Btc", "Operands": ["edx", "ecx"] }] +0FBB0425;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "eax"] }] +0FBB0C25;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "ecx"] }] +0FBB1425;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "edx"] }] +0FBA3805;[{ "Type": "Btc", "Operands": ["dword ptr [eax]", "0x05"] }] +0FBA3D05;[{ "Type": "Btc", "Operands": ["dword ptr [ebp]", "0x05"] }] + +# BSF - Bit Scan Forward +0FBCC1;[{ "Type": "Bsf", "Operands": ["eax", "ecx"] }] +0FBCD9;[{ "Type": "Bsf", "Operands": ["ebx", "ecx"] }] +0FBCCA;[{ "Type": "Bsf", "Operands": ["ecx", "edx"] }] +0FBC0425;[{ "Type": "Bsf", "Operands": ["eax", "dword ptr [eax]"] }] +0FBC0C25;[{ "Type": "Bsf", "Operands": ["ecx", "dword ptr [eax]"] }] +0FBC1425;[{ "Type": "Bsf", "Operands": ["edx", "dword ptr [eax]"] }] + +# BSR - Bit Scan Reverse +0FBDC1;[{ "Type": "Bsr", "Operands": ["eax", "ecx"] }] +0FBDD9;[{ "Type": "Bsr", "Operands": ["ebx", "ecx"] }] +0FBDCA;[{ "Type": "Bsr", "Operands": ["ecx", "edx"] }] +0FBD0425;[{ "Type": "Bsr", "Operands": ["eax", "dword ptr [eax]"] }] +0FBD0C25;[{ "Type": "Bsr", "Operands": ["ecx", "dword ptr [eax]"] }] +0FBD1425;[{ "Type": "Bsr", "Operands": ["edx", "dword ptr [eax]"] }] diff --git a/X86DisassemblerTests/TestData/call_tests.csv b/X86DisassemblerTests/TestData/call_tests.csv new file mode 100644 index 0000000..7a97a45 --- /dev/null +++ b/X86DisassemblerTests/TestData/call_tests.csv @@ -0,0 +1,68 @@ +# CALL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# CALL rel32 (opcode E8) +E810000000;[{ "Type": "Call", "Operands": ["0x00000015"] }] +E8FEFFFFFF;[{ "Type": "Call", "Operands": ["0x00000003"] }] + +# CALL r/m32 (opcode FF /2) with register operands +FFD0;[{ "Type": "Call", "Operands": ["eax"] }] +FFD1;[{ "Type": "Call", "Operands": ["ecx"] }] +FFD2;[{ "Type": "Call", "Operands": ["edx"] }] +FFD3;[{ "Type": "Call", "Operands": ["ebx"] }] +FFD4;[{ "Type": "Call", "Operands": ["esp"] }] +FFD5;[{ "Type": "Call", "Operands": ["ebp"] }] +FFD6;[{ "Type": "Call", "Operands": ["esi"] }] +FFD7;[{ "Type": "Call", "Operands": ["edi"] }] + +# CALL m32 (opcode FF /2) with memory operands +FF10;[{ "Type": "Call", "Operands": ["dword ptr [eax]"] }] +FF11;[{ "Type": "Call", "Operands": ["dword ptr [ecx]"] }] +FF12;[{ "Type": "Call", "Operands": ["dword ptr [edx]"] }] +FF13;[{ "Type": "Call", "Operands": ["dword ptr [ebx]"] }] +FF14;[{ "Type": "Call", "Operands": ["dword ptr [esp]"] }] +FF15;[{ "Type": "Call", "Operands": ["dword ptr [ebp]"] }] +FF16;[{ "Type": "Call", "Operands": ["dword ptr [esi]"] }] +FF17;[{ "Type": "Call", "Operands": ["dword ptr [edi]"] }] + +# CALL m32 (opcode FF /2) with SIB addressing +FF1400;[{ "Type": "Call", "Operands": ["dword ptr [eax+eax*1]"] }] +FF14C0;[{ "Type": "Call", "Operands": ["dword ptr [eax+eax*8]"] }] +FF1444;[{ "Type": "Call", "Operands": ["dword ptr [esp+eax*2]"] }] +FF1485;[{ "Type": "Call", "Operands": ["dword ptr [ebp+eax*4]"] }] +FF1498;[{ "Type": "Call", "Operands": ["dword ptr [eax+ebx*4]"] }] +FF14D9;[{ "Type": "Call", "Operands": ["dword ptr [ecx+ebx*8]"] }] +FF149D;[{ "Type": "Call", "Operands": ["dword ptr [ebp+ebx*4]"] }] + +# CALL m32 (opcode FF /2) with displacement +FF5000;[{ "Type": "Call", "Operands": ["dword ptr [eax+0x0]"] }] +FF5010;[{ "Type": "Call", "Operands": ["dword ptr [eax+0x10]"] }] +FF90FFFFFF7F;[{ "Type": "Call", "Operands": ["dword ptr [eax+0x7FFFFFFF]"] }] +FF9000000080;[{ "Type": "Call", "Operands": ["dword ptr [eax+0x80000000]"] }] + +# CALL m32 (opcode FF /2) with SIB and displacement +FF5400FF;[{ "Type": "Call", "Operands": ["dword ptr [eax+eax*1-0x1]"] }] +FF54C0FF;[{ "Type": "Call", "Operands": ["dword ptr [eax+eax*8-0x1]"] }] +FF5444FF;[{ "Type": "Call", "Operands": ["dword ptr [esp+eax*2-0x1]"] }] +FF5485FF;[{ "Type": "Call", "Operands": ["dword ptr [ebp+eax*4-0x1]"] }] +FF5498FF;[{ "Type": "Call", "Operands": ["dword ptr [eax+ebx*4-0x1]"] }] +FF54D9FF;[{ "Type": "Call", "Operands": ["dword ptr [ecx+ebx*8-0x1]"] }] +FF549DFF;[{ "Type": "Call", "Operands": ["dword ptr [ebp+ebx*4-0x1]"] }] + +# CALL m16:32 (opcode FF /3) - Far call with memory operand +FF1C;[{ "Type": "Call", "Operands": ["fword ptr [esp]"] }] +FF1D;[{ "Type": "Call", "Operands": ["fword ptr [ebp]"] }] +FF1E;[{ "Type": "Call", "Operands": ["fword ptr [esi]"] }] +FF1F;[{ "Type": "Call", "Operands": ["fword ptr [edi]"] }] + +# CALL m32 (opcode FF /2) with direct memory operand +FF1578563412;[{ "Type": "Call", "Operands": ["dword ptr [0x12345678]"] }] + +# CALL m32 (opcode FF /2) with segment override prefixes +26FF5510;[{ "Type": "Call", "Operands": ["dword ptr es:[ebp+0x10]"] }] +2EFF5510;[{ "Type": "Call", "Operands": ["dword ptr cs:[ebp+0x10]"] }] +36FF5510;[{ "Type": "Call", "Operands": ["dword ptr ss:[ebp+0x10]"] }] +3EFF5510;[{ "Type": "Call", "Operands": ["dword ptr ds:[ebp+0x10]"] }] +64FF5510;[{ "Type": "Call", "Operands": ["dword ptr fs:[ebp+0x10]"] }] +65FF5510;[{ "Type": "Call", "Operands": ["dword ptr gs:[ebp+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/cmp_tests.csv b/X86DisassemblerTests/TestData/cmp_tests.csv new file mode 100644 index 0000000..ddb7162 --- /dev/null +++ b/X86DisassemblerTests/TestData/cmp_tests.csv @@ -0,0 +1,25 @@ +# CMP instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# CMP r/m8, imm8 (opcode 80 /7) +80F842;[{ "Type": "Cmp", "Operands": ["al", "0x42"] }] + +# CMP r/m32, imm32 (opcode 81 /7) +81F878563412;[{ "Type": "Cmp", "Operands": ["eax", "0x12345678"] }] + +# CMP r/m32, imm8 (opcode 83 /7) +83F842;[{ "Type": "Cmp", "Operands": ["eax", "0x42"] }] + +# CMP with memory operands +813C2578563412;[{ "Type": "Cmp", "Operands": ["dword ptr [eax]", "0x12345678"] }] + +# CMP r/m32, r32 (opcode 39) +39D8;[{ "Type": "Cmp", "Operands": ["eax", "ebx"] }] +39CA;[{ "Type": "Cmp", "Operands": ["edx", "ecx"] }] +394B10;[{ "Type": "Cmp", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# CMP r32, r/m32 (opcode 3B) +3BD8;[{ "Type": "Cmp", "Operands": ["ebx", "eax"] }] +3BCA;[{ "Type": "Cmp", "Operands": ["ecx", "edx"] }] +3B4B10;[{ "Type": "Cmp", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/div_tests.csv b/X86DisassemblerTests/TestData/div_tests.csv new file mode 100644 index 0000000..b37bbcb --- /dev/null +++ b/X86DisassemblerTests/TestData/div_tests.csv @@ -0,0 +1,24 @@ +# DIV instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# DIV r/m8 (opcode F6 /6) +F6F0;[{ "Type": "Div", "Operands": ["al"] }] +F6F3;[{ "Type": "Div", "Operands": ["bl"] }] +F6F1;[{ "Type": "Div", "Operands": ["cl"] }] +F6F2;[{ "Type": "Div", "Operands": ["dl"] }] + +# DIV r/m32 (opcode F7 /6) +F7F0;[{ "Type": "Div", "Operands": ["eax"] }] +F7F3;[{ "Type": "Div", "Operands": ["ebx"] }] +F7F1;[{ "Type": "Div", "Operands": ["ecx"] }] +F7F2;[{ "Type": "Div", "Operands": ["edx"] }] +F7F4;[{ "Type": "Div", "Operands": ["esp"] }] +F7F5;[{ "Type": "Div", "Operands": ["ebp"] }] +F7F6;[{ "Type": "Div", "Operands": ["esi"] }] +F7F7;[{ "Type": "Div", "Operands": ["edi"] }] + +# DIV with memory operands +F63425;[{ "Type": "Div", "Operands": ["byte ptr [eax]"] }] +F73425;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }] +F7342510000000;[{ "Type": "Div", "Operands": ["dword ptr [eax+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/flag_tests.csv b/X86DisassemblerTests/TestData/flag_tests.csv new file mode 100644 index 0000000..1893c22 --- /dev/null +++ b/X86DisassemblerTests/TestData/flag_tests.csv @@ -0,0 +1,30 @@ +# Flag control instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# STC - Set Carry Flag +F9;[{ "Type": "Stc", "Operands": [] }] + +# CLC - Clear Carry Flag +F8;[{ "Type": "Clc", "Operands": [] }] + +# CMC - Complement Carry Flag +F5;[{ "Type": "Cmc", "Operands": [] }] + +# STD - Set Direction Flag +FD;[{ "Type": "Std", "Operands": [] }] + +# CLD - Clear Direction Flag +FC;[{ "Type": "Cld", "Operands": [] }] + +# STI - Set Interrupt Flag +FB;[{ "Type": "Sti", "Operands": [] }] + +# CLI - Clear Interrupt Flag +FA;[{ "Type": "Cli", "Operands": [] }] + +# SAHF - Store AH into Flags +9E;[{ "Type": "Sahf", "Operands": [] }] + +# LAHF - Load Flags into AH +9F;[{ "Type": "Lahf", "Operands": [] }] diff --git a/X86DisassemblerTests/TestData/fnstsw_tests.csv b/X86DisassemblerTests/TestData/fnstsw_tests.csv new file mode 100644 index 0000000..70236e6 --- /dev/null +++ b/X86DisassemblerTests/TestData/fnstsw_tests.csv @@ -0,0 +1,15 @@ +# FNSTSW instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# FNSTSW AX - Store FPU status word in AX without checking for pending unmasked exceptions +DFE0;[{ "Type": "Fnstsw", "Operands": ["ax"] }] + +# FSTSW AX - Store FPU status word in AX +9BDFE0;[{ "Type": "Fstsw", "Operands": ["ax"] }] + +# FSTSW m2byte - Store FPU status word to memory +9BDD3C25;[{ "Type": "Fstsw", "Operands": ["word ptr [eax]"] }] + +# FNSTSW m2byte - Store FPU status word to memory without checking for pending unmasked exceptions +DD3C25;[{ "Type": "Fnstsw", "Operands": ["word ptr [eax]"] }] diff --git a/X86DisassemblerTests/TestData/fpu_tests.csv b/X86DisassemblerTests/TestData/fpu_tests.csv new file mode 100644 index 0000000..6736007 --- /dev/null +++ b/X86DisassemblerTests/TestData/fpu_tests.csv @@ -0,0 +1,109 @@ +# Floating Point instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# Basic FPU instructions + +# FNSTSW AX - Store FPU status word in AX without checking for pending unmasked exceptions +DFE0;[{ "Type": "Fnstsw", "Operands": ["ax"] }] + +# FADD - Add floating point values +D8C0;[{ "Type": "Fadd", "Operands": ["ST(0)", "ST(0)"] }] +D8C1;[{ "Type": "Fadd", "Operands": ["ST(0)", "ST(1)"] }] +DCC0;[{ "Type": "Fadd", "Operands": ["ST(0)", "ST(0)"] }] +DCC1;[{ "Type": "Fadd", "Operands": ["ST(1)", "ST(0)"] }] +D8042510000000;[{ "Type": "Fadd", "Operands": ["dword ptr [0x10]"] }] +DC042510000000;[{ "Type": "Fadd", "Operands": ["qword ptr [0x10]"] }] + +# FSUB - Subtract floating point values +D8E0;[{ "Type": "Fsub", "Operands": ["ST(0)", "ST(0)"] }] +D8E1;[{ "Type": "Fsub", "Operands": ["ST(0)", "ST(1)"] }] +DCE8;[{ "Type": "Fsub", "Operands": ["ST(0)", "ST(0)"] }] +DCE9;[{ "Type": "Fsub", "Operands": ["ST(1)", "ST(0)"] }] +D8242510000000;[{ "Type": "Fsub", "Operands": ["dword ptr [0x10]"] }] +DC242510000000;[{ "Type": "Fsub", "Operands": ["qword ptr [0x10]"] }] + +# FSUBR - Subtract floating point values (reversed) +D8E8;[{ "Type": "Fsubr", "Operands": ["ST(0)", "ST(0)"] }] +D8E9;[{ "Type": "Fsubr", "Operands": ["ST(0)", "ST(1)"] }] +DCE0;[{ "Type": "Fsubr", "Operands": ["ST(0)", "ST(0)"] }] +DCE1;[{ "Type": "Fsubr", "Operands": ["ST(1)", "ST(0)"] }] +D82C2510000000;[{ "Type": "Fsubr", "Operands": ["dword ptr [0x10]"] }] +DC2C2510000000;[{ "Type": "Fsubr", "Operands": ["qword ptr [0x10]"] }] + +# FMUL - Multiply floating point values +D8C8;[{ "Type": "Fmul", "Operands": ["ST(0)", "ST(0)"] }] +D8C9;[{ "Type": "Fmul", "Operands": ["ST(0)", "ST(1)"] }] +DCC8;[{ "Type": "Fmul", "Operands": ["ST(0)", "ST(0)"] }] +DCC9;[{ "Type": "Fmul", "Operands": ["ST(1)", "ST(0)"] }] +D80C2510000000;[{ "Type": "Fmul", "Operands": ["dword ptr [0x10]"] }] +DC0C2510000000;[{ "Type": "Fmul", "Operands": ["qword ptr [0x10]"] }] + +# FDIV - Divide floating point values +D8F0;[{ "Type": "Fdiv", "Operands": ["ST(0)", "ST(0)"] }] +D8F1;[{ "Type": "Fdiv", "Operands": ["ST(0)", "ST(1)"] }] +DCF8;[{ "Type": "Fdiv", "Operands": ["ST(0)", "ST(0)"] }] +DCF9;[{ "Type": "Fdiv", "Operands": ["ST(1)", "ST(0)"] }] +D8342510000000;[{ "Type": "Fdiv", "Operands": ["dword ptr [0x10]"] }] +DC342510000000;[{ "Type": "Fdiv", "Operands": ["qword ptr [0x10]"] }] + +# FDIVR - Divide floating point values (reversed) +D8F8;[{ "Type": "Fdivr", "Operands": ["ST(0)", "ST(0)"] }] +D8F9;[{ "Type": "Fdivr", "Operands": ["ST(0)", "ST(1)"] }] +DCF0;[{ "Type": "Fdivr", "Operands": ["ST(0)", "ST(0)"] }] +DCF1;[{ "Type": "Fdivr", "Operands": ["ST(1)", "ST(0)"] }] +D83C2510000000;[{ "Type": "Fdivr", "Operands": ["dword ptr [0x10]"] }] +DC3C2510000000;[{ "Type": "Fdivr", "Operands": ["qword ptr [0x10]"] }] + +# FLD - Load floating point value +D9C0;[{ "Type": "Fld", "Operands": ["ST(0)"] }] +D9C1;[{ "Type": "Fld", "Operands": ["ST(1)"] }] +D9042510000000;[{ "Type": "Fld", "Operands": ["dword ptr [0x10]"] }] +DD042510000000;[{ "Type": "Fld", "Operands": ["qword ptr [0x10]"] }] +DB2C25;[{ "Type": "Fld", "Operands": ["tbyte ptr [eax]"] }] + +# FST - Store floating point value +D9D0;[{ "Type": "Fst", "Operands": ["ST(0)"] }] +D9D1;[{ "Type": "Fst", "Operands": ["ST(1)"] }] +D9142510000000;[{ "Type": "Fst", "Operands": ["dword ptr [0x10]"] }] +DD142510000000;[{ "Type": "Fst", "Operands": ["qword ptr [0x10]"] }] + +# FSTP - Store floating point value and pop +D9D8;[{ "Type": "Fstp", "Operands": ["ST(0)"] }] +D9D9;[{ "Type": "Fstp", "Operands": ["ST(1)"] }] +D91C2510000000;[{ "Type": "Fstp", "Operands": ["dword ptr [0x10]"] }] +DD1C2510000000;[{ "Type": "Fstp", "Operands": ["qword ptr [0x10]"] }] +DB3C25;[{ "Type": "Fstp", "Operands": ["tbyte ptr [eax]"] }] + +# FCOM - Compare floating point values +D8D0;[{ "Type": "Fcom", "Operands": ["ST(0)"] }] +D8D1;[{ "Type": "Fcom", "Operands": ["ST(1)"] }] +D8142510000000;[{ "Type": "Fcom", "Operands": ["dword ptr [0x10]"] }] +DC142510000000;[{ "Type": "Fcom", "Operands": ["qword ptr [0x10]"] }] + +# FCOMP - Compare floating point values and pop +D8D8;[{ "Type": "Fcomp", "Operands": ["ST(0)"] }] +D8D9;[{ "Type": "Fcomp", "Operands": ["ST(1)"] }] +D81C2510000000;[{ "Type": "Fcomp", "Operands": ["dword ptr [0x10]"] }] +DC1C2510000000;[{ "Type": "Fcomp", "Operands": ["qword ptr [0x10]"] }] + +# FCOMPP - Compare floating point values and pop twice +DED9;[{ "Type": "Fcompp", "Operands": [] }] + +# FCHS - Change sign of floating point value +D9E0;[{ "Type": "Fchs", "Operands": [] }] + +# FABS - Absolute value of floating point value +D9E1;[{ "Type": "Fabs", "Operands": [] }] + +# FTST - Test floating point value +D9E4;[{ "Type": "Ftst", "Operands": [] }] + +# FXAM - Examine floating point value +D9E5;[{ "Type": "Fxam", "Operands": [] }] + +# FINIT - Initialize FPU (with FWAIT prefix) +9BDBE3;[{ "Type": "Finit", "Operands": [] }] + +# FNINIT - Initialize FPU without checking for pending unmasked exceptions +DBE3;[{ "Type": "Fninit", "Operands": [] }] diff --git a/X86DisassemblerTests/TestData/group3_instruction_tests.csv b/X86DisassemblerTests/TestData/group3_instruction_tests.csv new file mode 100644 index 0000000..187976f --- /dev/null +++ b/X86DisassemblerTests/TestData/group3_instruction_tests.csv @@ -0,0 +1,60 @@ +# Group 3 instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# Group 3 instructions (opcode F6-F7 /0-/7) +# TEST, NOT, NEG, MUL, IMUL, DIV, IDIV + +# Group 3 with 8-bit register/memory (opcode F6) +# TEST r/m8, imm8 (opcode F6 /0) +F6C042;[{ "Type": "Test", "Operands": ["al", "0x42"] }] + +# NOT r/m8 (opcode F6 /2) +F6D0;[{ "Type": "Not", "Operands": ["al"] }] + +# NEG r/m8 (opcode F6 /3) +F6D8;[{ "Type": "Neg", "Operands": ["al"] }] + +# MUL r/m8 (opcode F6 /4) +F6E0;[{ "Type": "Mul", "Operands": ["al"] }] + +# IMUL r/m8 (opcode F6 /5) +F6E8;[{ "Type": "Imul", "Operands": ["al"] }] + +# DIV r/m8 (opcode F6 /6) +F6F0;[{ "Type": "Div", "Operands": ["al"] }] + +# IDIV r/m8 (opcode F6 /7) +F6F8;[{ "Type": "Idiv", "Operands": ["al"] }] + +# Group 3 with 32-bit register/memory (opcode F7) +# TEST r/m32, imm32 (opcode F7 /0) +F7C078563412;[{ "Type": "Test", "Operands": ["eax", "0x12345678"] }] + +# NOT r/m32 (opcode F7 /2) +F7D0;[{ "Type": "Not", "Operands": ["eax"] }] + +# NEG r/m32 (opcode F7 /3) +F7D8;[{ "Type": "Neg", "Operands": ["eax"] }] + +# MUL r/m32 (opcode F7 /4) +F7E0;[{ "Type": "Mul", "Operands": ["eax"] }] + +# IMUL r/m32 (opcode F7 /5) +F7E8;[{ "Type": "Imul", "Operands": ["eax"] }] + +# DIV r/m32 (opcode F7 /6) +F7F0;[{ "Type": "Div", "Operands": ["eax"] }] + +# IDIV r/m32 (opcode F7 /7) +F7F8;[{ "Type": "Idiv", "Operands": ["eax"] }] + +# Group 3 with memory operands +F6042542;[{ "Type": "Test", "Operands": ["byte ptr [eax]", "0x42"] }] +F7042578563412;[{ "Type": "Test", "Operands": ["dword ptr [eax]", "0x12345678"] }] +F71425;[{ "Type": "Not", "Operands": ["dword ptr [eax]"] }] +F71C25;[{ "Type": "Neg", "Operands": ["dword ptr [eax]"] }] +F72425;[{ "Type": "Mul", "Operands": ["dword ptr [eax]"] }] +F72C25;[{ "Type": "Imul", "Operands": ["dword ptr [eax]"] }] +F73425;[{ "Type": "Div", "Operands": ["dword ptr [eax]"] }] +F73C25;[{ "Type": "Idiv", "Operands": ["dword ptr [eax]"] }] diff --git a/X86DisassemblerTests/TestData/idiv_tests.csv b/X86DisassemblerTests/TestData/idiv_tests.csv new file mode 100644 index 0000000..21cdd45 --- /dev/null +++ b/X86DisassemblerTests/TestData/idiv_tests.csv @@ -0,0 +1,24 @@ +# IDIV instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# IDIV r/m8 (opcode F6 /7) +F6F8;[{ "Type": "IDiv", "Operands": ["al"] }] +F6FB;[{ "Type": "IDiv", "Operands": ["bl"] }] +F6F9;[{ "Type": "IDiv", "Operands": ["cl"] }] +F6FA;[{ "Type": "IDiv", "Operands": ["dl"] }] + +# IDIV r/m32 (opcode F7 /7) +F7F8;[{ "Type": "IDiv", "Operands": ["eax"] }] +F7FB;[{ "Type": "IDiv", "Operands": ["ebx"] }] +F7F9;[{ "Type": "IDiv", "Operands": ["ecx"] }] +F7FA;[{ "Type": "IDiv", "Operands": ["edx"] }] +F7FC;[{ "Type": "IDiv", "Operands": ["esp"] }] +F7FD;[{ "Type": "IDiv", "Operands": ["ebp"] }] +F7FE;[{ "Type": "IDiv", "Operands": ["esi"] }] +F7FF;[{ "Type": "IDiv", "Operands": ["edi"] }] + +# IDIV with memory operands +F63C25;[{ "Type": "IDiv", "Operands": ["byte ptr [eax]"] }] +F73C25;[{ "Type": "IDiv", "Operands": ["dword ptr [eax]"] }] +F73C2510000000;[{ "Type": "IDiv", "Operands": ["dword ptr [eax+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/imul_tests.csv b/X86DisassemblerTests/TestData/imul_tests.csv new file mode 100644 index 0000000..c60d286 --- /dev/null +++ b/X86DisassemblerTests/TestData/imul_tests.csv @@ -0,0 +1,41 @@ +# IMUL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# IMUL r/m8 (opcode F6 /5) +F6E8;[{ "Type": "IMul", "Operands": ["al"] }] +F6EB;[{ "Type": "IMul", "Operands": ["bl"] }] +F6E9;[{ "Type": "IMul", "Operands": ["cl"] }] +F6EA;[{ "Type": "IMul", "Operands": ["dl"] }] + +# IMUL r/m32 (opcode F7 /5) +F7E8;[{ "Type": "IMul", "Operands": ["eax"] }] +F7EB;[{ "Type": "IMul", "Operands": ["ebx"] }] +F7E9;[{ "Type": "IMul", "Operands": ["ecx"] }] +F7EA;[{ "Type": "IMul", "Operands": ["edx"] }] +F7EC;[{ "Type": "IMul", "Operands": ["esp"] }] +F7ED;[{ "Type": "IMul", "Operands": ["ebp"] }] +F7EE;[{ "Type": "IMul", "Operands": ["esi"] }] +F7EF;[{ "Type": "IMul", "Operands": ["edi"] }] + +# IMUL r32, r/m32 (opcode 0F AF) +0FAFC3;[{ "Type": "IMul", "Operands": ["eax", "ebx"] }] +0FAFD8;[{ "Type": "IMul", "Operands": ["ebx", "eax"] }] +0FAFC9;[{ "Type": "IMul", "Operands": ["ecx", "ecx"] }] + +# IMUL r32, r/m32, imm8 (opcode 6B) +6BC310;[{ "Type": "IMul", "Operands": ["eax", "ebx", "0x10"] }] +6BD810;[{ "Type": "IMul", "Operands": ["ebx", "eax", "0x10"] }] +6BC910;[{ "Type": "IMul", "Operands": ["ecx", "ecx", "0x10"] }] + +# IMUL r32, r/m32, imm32 (opcode 69) +69C378563412;[{ "Type": "IMul", "Operands": ["eax", "ebx", "0x12345678"] }] +69D878563412;[{ "Type": "IMul", "Operands": ["ebx", "eax", "0x12345678"] }] +69C978563412;[{ "Type": "IMul", "Operands": ["ecx", "ecx", "0x12345678"] }] + +# IMUL with memory operands +F62C25;[{ "Type": "IMul", "Operands": ["byte ptr [eax]"] }] +F72C25;[{ "Type": "IMul", "Operands": ["dword ptr [eax]"] }] +0FAF0425;[{ "Type": "IMul", "Operands": ["eax", "dword ptr [eax]"] }] +6B042510;[{ "Type": "IMul", "Operands": ["eax", "dword ptr [eax]", "0x10"] }] +69042578563412;[{ "Type": "IMul", "Operands": ["eax", "dword ptr [eax]", "0x12345678"] }] diff --git a/X86DisassemblerTests/TestData/jcc_tests.csv b/X86DisassemblerTests/TestData/jcc_tests.csv new file mode 100644 index 0000000..8bbca61 --- /dev/null +++ b/X86DisassemblerTests/TestData/jcc_tests.csv @@ -0,0 +1,39 @@ +# Conditional jump instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# One-byte conditional jumps (opcodes 70-7F) with rel8 +7010;[{ "Type": "Jo", "Operands": ["0x00000012"] }] +71FE;[{ "Type": "Jno", "Operands": ["0x00000000"] }] +7210;[{ "Type": "Jb", "Operands": ["0x00000012"] }] +73FE;[{ "Type": "Jae", "Operands": ["0x00000000"] }] +7410;[{ "Type": "Je", "Operands": ["0x00000012"] }] +75FE;[{ "Type": "Jne", "Operands": ["0x00000000"] }] +7610;[{ "Type": "Jbe", "Operands": ["0x00000012"] }] +77FE;[{ "Type": "Ja", "Operands": ["0x00000000"] }] +7810;[{ "Type": "Js", "Operands": ["0x00000012"] }] +79FE;[{ "Type": "Jns", "Operands": ["0x00000000"] }] +7A10;[{ "Type": "Jp", "Operands": ["0x00000012"] }] +7BFE;[{ "Type": "Jnp", "Operands": ["0x00000000"] }] +7C10;[{ "Type": "Jl", "Operands": ["0x00000012"] }] +7DFE;[{ "Type": "Jge", "Operands": ["0x00000000"] }] +7E10;[{ "Type": "Jle", "Operands": ["0x00000012"] }] +7FFE;[{ "Type": "Jg", "Operands": ["0x00000000"] }] + +# Two-byte conditional jumps (opcodes 0F 80-8F) with rel32 +0F8010000000;[{ "Type": "Jo", "Operands": ["0x00000016"] }] +0F81FEFFFFFF;[{ "Type": "Jno", "Operands": ["0x00000004"] }] +0F8210000000;[{ "Type": "Jb", "Operands": ["0x00000016"] }] +0F83FEFFFFFF;[{ "Type": "Jae", "Operands": ["0x00000004"] }] +0F8410000000;[{ "Type": "Je", "Operands": ["0x00000016"] }] +0F85FEFFFFFF;[{ "Type": "Jne", "Operands": ["0x00000004"] }] +0F8610000000;[{ "Type": "Jbe", "Operands": ["0x00000016"] }] +0F87FEFFFFFF;[{ "Type": "Ja", "Operands": ["0x00000004"] }] +0F8810000000;[{ "Type": "Js", "Operands": ["0x00000016"] }] +0F89FEFFFFFF;[{ "Type": "Jns", "Operands": ["0x00000004"] }] +0F8A10000000;[{ "Type": "Jp", "Operands": ["0x00000016"] }] +0F8BFEFFFFFF;[{ "Type": "Jnp", "Operands": ["0x00000004"] }] +0F8C10000000;[{ "Type": "Jl", "Operands": ["0x00000016"] }] +0F8DFEFFFFFF;[{ "Type": "Jge", "Operands": ["0x00000004"] }] +0F8E10000000;[{ "Type": "Jle", "Operands": ["0x00000016"] }] +0F8FFEFFFFFF;[{ "Type": "Jg", "Operands": ["0x00000004"] }] diff --git a/X86DisassemblerTests/TestData/jmp_tests.csv b/X86DisassemblerTests/TestData/jmp_tests.csv new file mode 100644 index 0000000..2b272ea --- /dev/null +++ b/X86DisassemblerTests/TestData/jmp_tests.csv @@ -0,0 +1,58 @@ +# JMP instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# JMP rel8 (opcode EB) +EB10;[{ "Type": "Jmp", "Operands": ["0x00000012"] }] +EBFE;[{ "Type": "Jmp", "Operands": ["0x00000000"] }] + +# JMP rel32 (opcode E9) +E910000000;[{ "Type": "Jmp", "Operands": ["0x00000015"] }] +E9FEFFFFFF;[{ "Type": "Jmp", "Operands": ["0x00000003"] }] + +# JMP r/m32 (opcode FF /4) with register operands +FFE0;[{ "Type": "Jmp", "Operands": ["eax"] }] +FFE1;[{ "Type": "Jmp", "Operands": ["ecx"] }] +FFE2;[{ "Type": "Jmp", "Operands": ["edx"] }] +FFE3;[{ "Type": "Jmp", "Operands": ["ebx"] }] +FFE4;[{ "Type": "Jmp", "Operands": ["esp"] }] +FFE5;[{ "Type": "Jmp", "Operands": ["ebp"] }] +FFE6;[{ "Type": "Jmp", "Operands": ["esi"] }] +FFE7;[{ "Type": "Jmp", "Operands": ["edi"] }] + +# JMP m32 (opcode FF /4) with memory operands +FF20;[{ "Type": "Jmp", "Operands": ["dword ptr [eax]"] }] +FF21;[{ "Type": "Jmp", "Operands": ["dword ptr [ecx]"] }] +FF22;[{ "Type": "Jmp", "Operands": ["dword ptr [edx]"] }] +FF23;[{ "Type": "Jmp", "Operands": ["dword ptr [ebx]"] }] +FF24;[{ "Type": "Jmp", "Operands": ["dword ptr [esp]"] }] +FF25;[{ "Type": "Jmp", "Operands": ["dword ptr [ebp]"] }] +FF26;[{ "Type": "Jmp", "Operands": ["dword ptr [esi]"] }] +FF27;[{ "Type": "Jmp", "Operands": ["dword ptr [edi]"] }] + +# JMP m32 (opcode FF /4) with displacement +FF6010;[{ "Type": "Jmp", "Operands": ["dword ptr [eax+0x10]"] }] +FF6110;[{ "Type": "Jmp", "Operands": ["dword ptr [ecx+0x10]"] }] +FF6210;[{ "Type": "Jmp", "Operands": ["dword ptr [edx+0x10]"] }] +FF6310;[{ "Type": "Jmp", "Operands": ["dword ptr [ebx+0x10]"] }] +FF6410;[{ "Type": "Jmp", "Operands": ["dword ptr [esp+0x10]"] }] +FF6510;[{ "Type": "Jmp", "Operands": ["dword ptr [ebp+0x10]"] }] +FF6610;[{ "Type": "Jmp", "Operands": ["dword ptr [esi+0x10]"] }] +FF6710;[{ "Type": "Jmp", "Operands": ["dword ptr [edi+0x10]"] }] + +# JMP m32 (opcode FF /4) with SIB byte +FF24C5;[{ "Type": "Jmp", "Operands": ["dword ptr [eax*8+ebp]"] }] +FF24CD;[{ "Type": "Jmp", "Operands": ["dword ptr [ecx*8+ebp]"] }] +FF24D5;[{ "Type": "Jmp", "Operands": ["dword ptr [edx*8+ebp]"] }] +FF24DD;[{ "Type": "Jmp", "Operands": ["dword ptr [ebx*8+ebp]"] }] + +# JMP m32 (opcode FF /4) with direct memory operand +FF2578563412;[{ "Type": "Jmp", "Operands": ["dword ptr [0x12345678]"] }] + +# JMP m32 (opcode FF /4) with segment override prefixes +26FF6510;[{ "Type": "Jmp", "Operands": ["dword ptr es:[ebp+0x10]"] }] +2EFF6510;[{ "Type": "Jmp", "Operands": ["dword ptr cs:[ebp+0x10]"] }] +36FF6510;[{ "Type": "Jmp", "Operands": ["dword ptr ss:[ebp+0x10]"] }] +3EFF6510;[{ "Type": "Jmp", "Operands": ["dword ptr ds:[ebp+0x10]"] }] +64FF6510;[{ "Type": "Jmp", "Operands": ["dword ptr fs:[ebp+0x10]"] }] +65FF6510;[{ "Type": "Jmp", "Operands": ["dword ptr gs:[ebp+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/lea_tests.csv b/X86DisassemblerTests/TestData/lea_tests.csv new file mode 100644 index 0000000..9323a4b --- /dev/null +++ b/X86DisassemblerTests/TestData/lea_tests.csv @@ -0,0 +1,64 @@ +# LEA instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# LEA r32, m (opcode 8D) with basic addressing modes +8D00;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [eax]"] }] +8D01;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ecx]"] }] +8D02;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edx]"] }] +8D03;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx]"] }] +8D05;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp]"] }] +8D06;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esi]"] }] +8D07;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edi]"] }] + +# LEA r32, m (opcode 8D) with displacement +8D4010;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [eax+0x10]"] }] +8D4110;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ecx+0x10]"] }] +8D4210;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edx+0x10]"] }] +8D4310;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx+0x10]"] }] +8D4510;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp+0x10]"] }] +8D4610;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esi+0x10]"] }] +8D4710;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edi+0x10]"] }] + +# LEA r32, m (opcode 8D) with negative displacement +8D40F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [eax-0x10]"] }] +8D41F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ecx-0x10]"] }] +8D42F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edx-0x10]"] }] +8D43F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx-0x10]"] }] +8D45F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebp-0x10]"] }] +8D46F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esi-0x10]"] }] +8D47F0;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edi-0x10]"] }] + +# LEA r32, m (opcode 8D) with SIB byte (no displacement) +8D0424;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esp]"] }] +8D04CD;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ecx*8+ebp]"] }] +8D04D5;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edx*8+ebp]"] }] +8D04DD;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx*8+ebp]"] }] + +# LEA r32, m (opcode 8D) with SIB byte and displacement +8D442410;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [esp+0x10]"] }] +8D44CD10;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ecx*8+ebp+0x10]"] }] +8D44D510;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [edx*8+ebp+0x10]"] }] +8D44DD10;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx*8+ebp+0x10]"] }] + +# LEA r32, m (opcode 8D) with direct memory operand +8D0578563412;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [0x12345678]"] }] +8D1D78563412;[{ "Type": "Lea", "Operands": ["ebx", "dword ptr [0x12345678]"] }] +8D0D78563412;[{ "Type": "Lea", "Operands": ["ecx", "dword ptr [0x12345678]"] }] +8D1578563412;[{ "Type": "Lea", "Operands": ["edx", "dword ptr [0x12345678]"] }] + +# LEA with different destination registers +8DC3;[{ "Type": "Lea", "Operands": ["eax", "dword ptr [ebx]"] }] +8DCB;[{ "Type": "Lea", "Operands": ["ecx", "dword ptr [ebx]"] }] +8DD3;[{ "Type": "Lea", "Operands": ["edx", "dword ptr [ebx]"] }] +8DDB;[{ "Type": "Lea", "Operands": ["ebx", "dword ptr [ebx]"] }] +8DE3;[{ "Type": "Lea", "Operands": ["esp", "dword ptr [ebx]"] }] +8DEB;[{ "Type": "Lea", "Operands": ["ebp", "dword ptr [ebx]"] }] +8DF3;[{ "Type": "Lea", "Operands": ["esi", "dword ptr [ebx]"] }] +8DFB;[{ "Type": "Lea", "Operands": ["edi", "dword ptr [ebx]"] }] + +# LEA with complex addressing modes +8D8C8D78563412;[{ "Type": "Lea", "Operands": ["ecx", "dword ptr [ebp+ecx*4+0x12345678]"] }] +8D942D78563412;[{ "Type": "Lea", "Operands": ["edx", "dword ptr [ebp+ebp+0x12345678]"] }] +8D9C1D78563412;[{ "Type": "Lea", "Operands": ["ebx", "dword ptr [ebp+ebx+0x12345678]"] }] +8DA41D78563412;[{ "Type": "Lea", "Operands": ["esp", "dword ptr [ebp+ebx+0x12345678]"] }] diff --git a/X86DisassemblerTests/TestData/misc_tests.csv b/X86DisassemblerTests/TestData/misc_tests.csv new file mode 100644 index 0000000..163c62f --- /dev/null +++ b/X86DisassemblerTests/TestData/misc_tests.csv @@ -0,0 +1,52 @@ +# Miscellaneous instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# NOP - No Operation +90;[{ "Type": "Nop", "Operands": [] }] + +# INT - Call to Interrupt Procedure +CD03;[{ "Type": "Int", "Operands": ["0x03"] }] +CD10;[{ "Type": "Int", "Operands": ["0x10"] }] +CD21;[{ "Type": "Int", "Operands": ["0x21"] }] +CD80;[{ "Type": "Int", "Operands": ["0x80"] }] + +# INT3 - Breakpoint +CC;[{ "Type": "Int3", "Operands": [] }] + +# INTO - Call to Interrupt Procedure if Overflow Flag is Set +CE;[{ "Type": "Into", "Operands": [] }] + +# IRET/IRETD - Return from Interrupt +CF;[{ "Type": "Iret", "Operands": [] }] + +# CPUID - CPU Identification +0FA2;[{ "Type": "Cpuid", "Operands": [] }] + +# RDTSC - Read Time-Stamp Counter +0F31;[{ "Type": "Rdtsc", "Operands": [] }] + +# HLT - Halt +F4;[{ "Type": "Hlt", "Operands": [] }] + +# WAIT/FWAIT - Wait +9B;[{ "Type": "Wait", "Operands": [] }] + +# LOCK prefix +F0;[{ "Type": "Lock", "Operands": [] }] +F0FE05;[{ "Type": "Inc", "Operands": ["byte ptr [ebp]"], "Prefix": "Lock" }] +F0FF05;[{ "Type": "Inc", "Operands": ["dword ptr [ebp]"], "Prefix": "Lock" }] +F0FE0D;[{ "Type": "Dec", "Operands": ["byte ptr [ebp]"], "Prefix": "Lock" }] +F0FF0D;[{ "Type": "Dec", "Operands": ["dword ptr [ebp]"], "Prefix": "Lock" }] + +# IN - Input from Port +E410;[{ "Type": "In", "Operands": ["al", "0x10"] }] +E510;[{ "Type": "In", "Operands": ["eax", "0x10"] }] +EC;[{ "Type": "In", "Operands": ["al", "dx"] }] +ED;[{ "Type": "In", "Operands": ["eax", "dx"] }] + +# OUT - Output to Port +E610;[{ "Type": "Out", "Operands": ["0x10", "al"] }] +E710;[{ "Type": "Out", "Operands": ["0x10", "eax"] }] +EE;[{ "Type": "Out", "Operands": ["dx", "al"] }] +EF;[{ "Type": "Out", "Operands": ["dx", "eax"] }] diff --git a/X86DisassemblerTests/TestData/mov_tests.csv b/X86DisassemblerTests/TestData/mov_tests.csv new file mode 100644 index 0000000..d09f46a --- /dev/null +++ b/X86DisassemblerTests/TestData/mov_tests.csv @@ -0,0 +1,91 @@ +# MOV instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# MOV r8, imm8 (opcodes B0-B7) +B042;[{ "Type": "Mov", "Operands": ["al", "0x42"] }] +B142;[{ "Type": "Mov", "Operands": ["cl", "0x42"] }] +B242;[{ "Type": "Mov", "Operands": ["dl", "0x42"] }] +B342;[{ "Type": "Mov", "Operands": ["bl", "0x42"] }] +B442;[{ "Type": "Mov", "Operands": ["ah", "0x42"] }] +B542;[{ "Type": "Mov", "Operands": ["ch", "0x42"] }] +B642;[{ "Type": "Mov", "Operands": ["dh", "0x42"] }] +B742;[{ "Type": "Mov", "Operands": ["bh", "0x42"] }] + +# MOV r32, imm32 (opcodes B8-BF) +B878563412;[{ "Type": "Mov", "Operands": ["eax", "0x12345678"] }] +B978563412;[{ "Type": "Mov", "Operands": ["ecx", "0x12345678"] }] +BA78563412;[{ "Type": "Mov", "Operands": ["edx", "0x12345678"] }] +BB78563412;[{ "Type": "Mov", "Operands": ["ebx", "0x12345678"] }] +BC78563412;[{ "Type": "Mov", "Operands": ["esp", "0x12345678"] }] +BD78563412;[{ "Type": "Mov", "Operands": ["ebp", "0x12345678"] }] +BE78563412;[{ "Type": "Mov", "Operands": ["esi", "0x12345678"] }] +BF78563412;[{ "Type": "Mov", "Operands": ["edi", "0x12345678"] }] + +# MOV r/m8, r8 (opcode 88) +8801;[{ "Type": "Mov", "Operands": ["byte ptr [ecx]", "al"] }] +8803;[{ "Type": "Mov", "Operands": ["byte ptr [ebx]", "al"] }] +8805;[{ "Type": "Mov", "Operands": ["byte ptr [ebp]", "al"] }] +8807;[{ "Type": "Mov", "Operands": ["byte ptr [edi]", "al"] }] +8841FF;[{ "Type": "Mov", "Operands": ["byte ptr [ecx-0x1]", "al"] }] +8843FF;[{ "Type": "Mov", "Operands": ["byte ptr [ebx-0x1]", "al"] }] +8845FF;[{ "Type": "Mov", "Operands": ["byte ptr [ebp-0x1]", "al"] }] +8847FF;[{ "Type": "Mov", "Operands": ["byte ptr [edi-0x1]", "al"] }] + +# MOV r/m32, r32 (opcode 89) +8901;[{ "Type": "Mov", "Operands": ["dword ptr [ecx]", "eax"] }] +8903;[{ "Type": "Mov", "Operands": ["dword ptr [ebx]", "eax"] }] +8905;[{ "Type": "Mov", "Operands": ["dword ptr [ebp]", "eax"] }] +8907;[{ "Type": "Mov", "Operands": ["dword ptr [edi]", "eax"] }] +8941FF;[{ "Type": "Mov", "Operands": ["dword ptr [ecx-0x1]", "eax"] }] +8943FF;[{ "Type": "Mov", "Operands": ["dword ptr [ebx-0x1]", "eax"] }] +8945FF;[{ "Type": "Mov", "Operands": ["dword ptr [ebp-0x1]", "eax"] }] +8947FF;[{ "Type": "Mov", "Operands": ["dword ptr [edi-0x1]", "eax"] }] + +# MOV r8, r/m8 (opcode 8A) +8A01;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ecx]"] }] +8A03;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ebx]"] }] +8A05;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ebp]"] }] +8A07;[{ "Type": "Mov", "Operands": ["al", "byte ptr [edi]"] }] +8A41FF;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ecx-0x1]"] }] +8A43FF;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ebx-0x1]"] }] +8A45FF;[{ "Type": "Mov", "Operands": ["al", "byte ptr [ebp-0x1]"] }] +8A47FF;[{ "Type": "Mov", "Operands": ["al", "byte ptr [edi-0x1]"] }] + +# MOV r32, r/m32 (opcode 8B) +8B01;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ecx]"] }] +8B03;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ebx]"] }] +8B05;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ebp]"] }] +8B07;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [edi]"] }] +8B41FF;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ecx-0x1]"] }] +8B43FF;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ebx-0x1]"] }] +8B45FF;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [ebp-0x1]"] }] +8B47FF;[{ "Type": "Mov", "Operands": ["eax", "dword ptr [edi-0x1]"] }] + +# MOV r/m8, imm8 (opcode C6 /0) +C60142;[{ "Type": "Mov", "Operands": ["byte ptr [ecx]", "0x42"] }] +C60342;[{ "Type": "Mov", "Operands": ["byte ptr [ebx]", "0x42"] }] +C60542;[{ "Type": "Mov", "Operands": ["byte ptr [ebp]", "0x42"] }] +C60742;[{ "Type": "Mov", "Operands": ["byte ptr [edi]", "0x42"] }] +C641FF42;[{ "Type": "Mov", "Operands": ["byte ptr [ecx-0x1]", "0x42"] }] +C643FF42;[{ "Type": "Mov", "Operands": ["byte ptr [ebx-0x1]", "0x42"] }] +C645FF42;[{ "Type": "Mov", "Operands": ["byte ptr [ebp-0x1]", "0x42"] }] +C647FF42;[{ "Type": "Mov", "Operands": ["byte ptr [edi-0x1]", "0x42"] }] + +# MOV r/m32, imm32 (opcode C7 /0) +C70178563412;[{ "Type": "Mov", "Operands": ["dword ptr [ecx]", "0x12345678"] }] +C70378563412;[{ "Type": "Mov", "Operands": ["dword ptr [ebx]", "0x12345678"] }] +C70578563412;[{ "Type": "Mov", "Operands": ["dword ptr [ebp]", "0x12345678"] }] +C70778563412;[{ "Type": "Mov", "Operands": ["dword ptr [edi]", "0x12345678"] }] +C741FF78563412;[{ "Type": "Mov", "Operands": ["dword ptr [ecx-0x1]", "0x12345678"] }] +C743FF78563412;[{ "Type": "Mov", "Operands": ["dword ptr [ebx-0x1]", "0x12345678"] }] +C745FF78563412;[{ "Type": "Mov", "Operands": ["dword ptr [ebp-0x1]", "0x12345678"] }] +C747FF78563412;[{ "Type": "Mov", "Operands": ["dword ptr [edi-0x1]", "0x12345678"] }] + +# MOV with segment override prefixes +268B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr es:[ebp+0x10]"] }] +2E8B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr cs:[ebp+0x10]"] }] +368B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr ss:[ebp+0x10]"] }] +3E8B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr ds:[ebp+0x10]"] }] +648B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr fs:[ebp+0x10]"] }] +658B4510;[{ "Type": "Mov", "Operands": ["eax", "dword ptr gs:[ebp+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/mul_tests.csv b/X86DisassemblerTests/TestData/mul_tests.csv new file mode 100644 index 0000000..c703a06 --- /dev/null +++ b/X86DisassemblerTests/TestData/mul_tests.csv @@ -0,0 +1,24 @@ +# MUL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# MUL r/m8 (opcode F6 /4) +F6E0;[{ "Type": "Mul", "Operands": ["al"] }] +F6E3;[{ "Type": "Mul", "Operands": ["bl"] }] +F6E1;[{ "Type": "Mul", "Operands": ["cl"] }] +F6E2;[{ "Type": "Mul", "Operands": ["dl"] }] + +# MUL r/m32 (opcode F7 /4) +F7E0;[{ "Type": "Mul", "Operands": ["eax"] }] +F7E3;[{ "Type": "Mul", "Operands": ["ebx"] }] +F7E1;[{ "Type": "Mul", "Operands": ["ecx"] }] +F7E2;[{ "Type": "Mul", "Operands": ["edx"] }] +F7E4;[{ "Type": "Mul", "Operands": ["esp"] }] +F7E5;[{ "Type": "Mul", "Operands": ["ebp"] }] +F7E6;[{ "Type": "Mul", "Operands": ["esi"] }] +F7E7;[{ "Type": "Mul", "Operands": ["edi"] }] + +# MUL with memory operands +F62425;[{ "Type": "Mul", "Operands": ["byte ptr [eax]"] }] +F72425;[{ "Type": "Mul", "Operands": ["dword ptr [eax]"] }] +F7242510000000;[{ "Type": "Mul", "Operands": ["dword ptr [eax+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/neg_tests.csv b/X86DisassemblerTests/TestData/neg_tests.csv new file mode 100644 index 0000000..6cbf52f --- /dev/null +++ b/X86DisassemblerTests/TestData/neg_tests.csv @@ -0,0 +1,24 @@ +# NEG instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# NEG r/m8 (opcode F6 /3) +F6D8;[{ "Type": "Neg", "Operands": ["al"] }] +F6DB;[{ "Type": "Neg", "Operands": ["bl"] }] +F6D9;[{ "Type": "Neg", "Operands": ["cl"] }] +F6DA;[{ "Type": "Neg", "Operands": ["dl"] }] + +# NEG r/m32 (opcode F7 /3) +F7D8;[{ "Type": "Neg", "Operands": ["eax"] }] +F7DB;[{ "Type": "Neg", "Operands": ["ebx"] }] +F7D9;[{ "Type": "Neg", "Operands": ["ecx"] }] +F7DA;[{ "Type": "Neg", "Operands": ["edx"] }] +F7DC;[{ "Type": "Neg", "Operands": ["esp"] }] +F7DD;[{ "Type": "Neg", "Operands": ["ebp"] }] +F7DE;[{ "Type": "Neg", "Operands": ["esi"] }] +F7DF;[{ "Type": "Neg", "Operands": ["edi"] }] + +# NEG with memory operands +F61C25;[{ "Type": "Neg", "Operands": ["byte ptr [eax]"] }] +F71C25;[{ "Type": "Neg", "Operands": ["dword ptr [eax]"] }] +F71C2510000000;[{ "Type": "Neg", "Operands": ["dword ptr [eax+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/nop_tests.csv b/X86DisassemblerTests/TestData/nop_tests.csv index 6f8a790..b2e2902 100644 --- a/X86DisassemblerTests/TestData/nop_tests.csv +++ b/X86DisassemblerTests/TestData/nop_tests.csv @@ -3,29 +3,29 @@ RawBytes;Instructions # Basic NOP instruction (1-byte) -90;[{ "Mnemonic": "nop", "Operands": "" }] +90;[{ "Type": "Nop", "Operands": [] }] # Multi-byte NOP instructions (used for alignment) # 2-byte NOP (xchg AX, AX) -6690;[{ "Mnemonic": "nop", "Operands": "" }] +6690;[{ "Type": "Nop", "Operands": [] }] # 3-byte NOP (XCHG EAX, EAX) -0F1F00;[{ "Mnemonic": "nop", "Operands": "dword ptr [eax]" }] +0F1F00;[{ "Type": "Nop", "Operands": ["dword ptr [eax]"] }] # 4-byte NOP -0F1F4000;[{ "Mnemonic": "nop", "Operands": "dword ptr [eax]" }] +0F1F4000;[{ "Type": "Nop", "Operands": ["dword ptr [eax]"] }] # 5-byte NOP -0F1F440000;[{ "Mnemonic": "nop", "Operands": "dword ptr [eax+eax*1]" }] +0F1F440000;[{ "Type": "Nop", "Operands": ["dword ptr [eax+eax*1]"] }] # 6-byte NOP -660F1F440000;[{ "Mnemonic": "nop", "Operands": "word ptr [eax+eax*1]" }] +660F1F440000;[{ "Type": "Nop", "Operands": ["word ptr [eax+eax*1]"] }] # 7-byte NOP -0F1F8000000000;[{ "Mnemonic": "nop", "Operands": "dword ptr [eax]" }] +0F1F8000000000;[{ "Type": "Nop", "Operands": ["dword ptr [eax]"] }] # 8-byte NOP -0F1F840000000000;[{ "Mnemonic": "nop", "Operands": "dword ptr [eax+eax*1]" }] +0F1F840000000000;[{ "Type": "Nop", "Operands": ["dword ptr [eax+eax*1]"] }] # 9-byte NOP -660F1F840000000000;[{ "Mnemonic": "nop", "Operands": "word ptr [eax+eax*1]" }] +660F1F840000000000;[{ "Type": "Nop", "Operands": ["word ptr [eax+eax*1]"] }] diff --git a/X86DisassemblerTests/TestData/not_tests.csv b/X86DisassemblerTests/TestData/not_tests.csv new file mode 100644 index 0000000..a85c84d --- /dev/null +++ b/X86DisassemblerTests/TestData/not_tests.csv @@ -0,0 +1,24 @@ +# NOT instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# NOT r/m8 (opcode F6 /2) +F6D0;[{ "Type": "Not", "Operands": ["al"] }] +F6D3;[{ "Type": "Not", "Operands": ["bl"] }] +F6D1;[{ "Type": "Not", "Operands": ["cl"] }] +F6D2;[{ "Type": "Not", "Operands": ["dl"] }] + +# NOT r/m32 (opcode F7 /2) +F7D0;[{ "Type": "Not", "Operands": ["eax"] }] +F7D3;[{ "Type": "Not", "Operands": ["ebx"] }] +F7D1;[{ "Type": "Not", "Operands": ["ecx"] }] +F7D2;[{ "Type": "Not", "Operands": ["edx"] }] +F7D4;[{ "Type": "Not", "Operands": ["esp"] }] +F7D5;[{ "Type": "Not", "Operands": ["ebp"] }] +F7D6;[{ "Type": "Not", "Operands": ["esi"] }] +F7D7;[{ "Type": "Not", "Operands": ["edi"] }] + +# NOT with memory operands +F61425;[{ "Type": "Not", "Operands": ["byte ptr [eax]"] }] +F71425;[{ "Type": "Not", "Operands": ["dword ptr [eax]"] }] +F7142510000000;[{ "Type": "Not", "Operands": ["dword ptr [eax+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/or_tests.csv b/X86DisassemblerTests/TestData/or_tests.csv new file mode 100644 index 0000000..cac9830 --- /dev/null +++ b/X86DisassemblerTests/TestData/or_tests.csv @@ -0,0 +1,25 @@ +# OR instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# OR r/m8, imm8 (opcode 80 /1) +80C842;[{ "Type": "Or", "Operands": ["al", "0x42"] }] + +# OR r/m32, imm32 (opcode 81 /1) +81C878563412;[{ "Type": "Or", "Operands": ["eax", "0x12345678"] }] + +# OR r/m32, imm8 (opcode 83 /1) +83C842;[{ "Type": "Or", "Operands": ["eax", "0x42"] }] + +# OR with memory operands +810C2578563412;[{ "Type": "Or", "Operands": ["dword ptr [eax]", "0x12345678"] }] + +# OR r/m32, r32 (opcode 09) +09D8;[{ "Type": "Or", "Operands": ["eax", "ebx"] }] +09CA;[{ "Type": "Or", "Operands": ["edx", "ecx"] }] +094B10;[{ "Type": "Or", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# OR r32, r/m32 (opcode 0B) +0BD8;[{ "Type": "Or", "Operands": ["ebx", "eax"] }] +0BCA;[{ "Type": "Or", "Operands": ["ecx", "edx"] }] +0B4B10;[{ "Type": "Or", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/popreg_tests.csv b/X86DisassemblerTests/TestData/popreg_tests.csv index c0ee69c..6ccd994 100644 --- a/X86DisassemblerTests/TestData/popreg_tests.csv +++ b/X86DisassemblerTests/TestData/popreg_tests.csv @@ -1,9 +1,13 @@ +# POP register tests +# Format: RawBytes;Instructions RawBytes;Instructions -58;[{ "Mnemonic": "pop", "Operands": "eax" }] -59;[{ "Mnemonic": "pop", "Operands": "ecx" }] -5A;[{ "Mnemonic": "pop", "Operands": "edx" }] -5B;[{ "Mnemonic": "pop", "Operands": "ebx" }] -5C;[{ "Mnemonic": "pop", "Operands": "esp" }] -5D;[{ "Mnemonic": "pop", "Operands": "ebp" }] -5E;[{ "Mnemonic": "pop", "Operands": "esi" }] -5F;[{ "Mnemonic": "pop", "Operands": "edi" }] \ No newline at end of file + +# POP r32 (opcodes 58-5F) +58;[{ "Type": "Pop", "Operands": ["eax"] }] +59;[{ "Type": "Pop", "Operands": ["ecx"] }] +5A;[{ "Type": "Pop", "Operands": ["edx"] }] +5B;[{ "Type": "Pop", "Operands": ["ebx"] }] +5C;[{ "Type": "Pop", "Operands": ["esp"] }] +5D;[{ "Type": "Pop", "Operands": ["ebp"] }] +5E;[{ "Type": "Pop", "Operands": ["esi"] }] +5F;[{ "Type": "Pop", "Operands": ["edi"] }] \ No newline at end of file diff --git a/X86DisassemblerTests/TestData/poprm_tests.csv b/X86DisassemblerTests/TestData/poprm_tests.csv new file mode 100644 index 0000000..5f33543 --- /dev/null +++ b/X86DisassemblerTests/TestData/poprm_tests.csv @@ -0,0 +1,40 @@ +# POP r/m32 instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# POP r/m32 (opcode 8F /0) with register operands +8F00;[{ "Type": "Pop", "Operands": ["dword ptr [eax]"] }] +8F01;[{ "Type": "Pop", "Operands": ["dword ptr [ecx]"] }] +8F02;[{ "Type": "Pop", "Operands": ["dword ptr [edx]"] }] +8F03;[{ "Type": "Pop", "Operands": ["dword ptr [ebx]"] }] +8F04;[{ "Type": "Pop", "Operands": ["dword ptr [esp]"] }] +8F05;[{ "Type": "Pop", "Operands": ["dword ptr [ebp]"] }] +8F06;[{ "Type": "Pop", "Operands": ["dword ptr [esi]"] }] +8F07;[{ "Type": "Pop", "Operands": ["dword ptr [edi]"] }] + +# POP r/m32 (opcode 8F /0) with memory operands and displacement +8F4010;[{ "Type": "Pop", "Operands": ["dword ptr [eax+0x10]"] }] +8F4110;[{ "Type": "Pop", "Operands": ["dword ptr [ecx+0x10]"] }] +8F4210;[{ "Type": "Pop", "Operands": ["dword ptr [edx+0x10]"] }] +8F4310;[{ "Type": "Pop", "Operands": ["dword ptr [ebx+0x10]"] }] +8F4410;[{ "Type": "Pop", "Operands": ["dword ptr [esp+0x10]"] }] +8F4510;[{ "Type": "Pop", "Operands": ["dword ptr [ebp+0x10]"] }] +8F4610;[{ "Type": "Pop", "Operands": ["dword ptr [esi+0x10]"] }] +8F4710;[{ "Type": "Pop", "Operands": ["dword ptr [edi+0x10]"] }] + +# POP r/m32 (opcode 8F /0) with SIB byte +8F04C5;[{ "Type": "Pop", "Operands": ["dword ptr [eax*8+ebp]"] }] +8F04CD;[{ "Type": "Pop", "Operands": ["dword ptr [ecx*8+ebp]"] }] +8F04D5;[{ "Type": "Pop", "Operands": ["dword ptr [edx*8+ebp]"] }] +8F04DD;[{ "Type": "Pop", "Operands": ["dword ptr [ebx*8+ebp]"] }] + +# POP r/m32 (opcode 8F /0) with direct memory operand +8F0578563412;[{ "Type": "Pop", "Operands": ["dword ptr [0x12345678]"] }] + +# POP r/m32 (opcode 8F /0) with segment override prefixes +268F4510;[{ "Type": "Pop", "Operands": ["dword ptr es:[ebp+0x10]"] }] +2E8F4510;[{ "Type": "Pop", "Operands": ["dword ptr cs:[ebp+0x10]"] }] +368F4510;[{ "Type": "Pop", "Operands": ["dword ptr ss:[ebp+0x10]"] }] +3E8F4510;[{ "Type": "Pop", "Operands": ["dword ptr ds:[ebp+0x10]"] }] +648F4510;[{ "Type": "Pop", "Operands": ["dword ptr fs:[ebp+0x10]"] }] +658F4510;[{ "Type": "Pop", "Operands": ["dword ptr gs:[ebp+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/pushimm_tests.csv b/X86DisassemblerTests/TestData/pushimm_tests.csv index ee3e9a4..33fa8b9 100644 --- a/X86DisassemblerTests/TestData/pushimm_tests.csv +++ b/X86DisassemblerTests/TestData/pushimm_tests.csv @@ -1,3 +1,19 @@ +# PUSH immediate instruction tests +# Format: RawBytes;Instructions RawBytes;Instructions -6878563412;[{ "Mnemonic": "push", "Operands": "0x12345678" }] -6A10;[{ "Mnemonic": "push", "Operands": "0x10" }] + +# PUSH imm32 (32-bit immediate) +6878563412;[{ "Type": "Push", "Operands": ["0x12345678"] }] + +# PUSH imm8 (8-bit immediate) +6A10;[{ "Type": "Push", "Operands": ["0x10"] }] +6A00;[{ "Type": "Push", "Operands": ["0x00"] }] +6AFF;[{ "Type": "Push", "Operands": ["0xFF"] }] + +# PUSH imm32 with various values +6800000000;[{ "Type": "Push", "Operands": ["0x00000000"] }] +68FFFFFFFF;[{ "Type": "Push", "Operands": ["0xFFFFFFFF"] }] +6801000000;[{ "Type": "Push", "Operands": ["0x00000001"] }] + +# PUSH imm16 with operand size prefix +66687856;[{ "Type": "Push", "Operands": ["0x5678"] }] diff --git a/X86DisassemblerTests/TestData/pushreg_tests.csv b/X86DisassemblerTests/TestData/pushreg_tests.csv index c8261d9..357a3a6 100644 --- a/X86DisassemblerTests/TestData/pushreg_tests.csv +++ b/X86DisassemblerTests/TestData/pushreg_tests.csv @@ -1,9 +1,13 @@ +# PUSH register tests +# Format: RawBytes;Instructions RawBytes;Instructions -50;[{ "Mnemonic": "push", "Operands": "eax" }] -51;[{ "Mnemonic": "push", "Operands": "ecx" }] -52;[{ "Mnemonic": "push", "Operands": "edx" }] -53;[{ "Mnemonic": "push", "Operands": "ebx" }] -54;[{ "Mnemonic": "push", "Operands": "esp" }] -55;[{ "Mnemonic": "push", "Operands": "ebp" }] -56;[{ "Mnemonic": "push", "Operands": "esi" }] -57;[{ "Mnemonic": "push", "Operands": "edi" }] \ No newline at end of file + +# PUSH r32 (opcodes 50-57) +50;[{ "Type": "Push", "Operands": ["eax"] }] +51;[{ "Type": "Push", "Operands": ["ecx"] }] +52;[{ "Type": "Push", "Operands": ["edx"] }] +53;[{ "Type": "Push", "Operands": ["ebx"] }] +54;[{ "Type": "Push", "Operands": ["esp"] }] +55;[{ "Type": "Push", "Operands": ["ebp"] }] +56;[{ "Type": "Push", "Operands": ["esi"] }] +57;[{ "Type": "Push", "Operands": ["edi"] }] \ No newline at end of file diff --git a/X86DisassemblerTests/TestData/pushrm_tests.csv b/X86DisassemblerTests/TestData/pushrm_tests.csv new file mode 100644 index 0000000..75ed398 --- /dev/null +++ b/X86DisassemblerTests/TestData/pushrm_tests.csv @@ -0,0 +1,40 @@ +# PUSH r/m32 instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# PUSH r/m32 (opcode FF /6) with register operands +FF30;[{ "Type": "Push", "Operands": ["dword ptr [eax]"] }] +FF31;[{ "Type": "Push", "Operands": ["dword ptr [ecx]"] }] +FF32;[{ "Type": "Push", "Operands": ["dword ptr [edx]"] }] +FF33;[{ "Type": "Push", "Operands": ["dword ptr [ebx]"] }] +FF34;[{ "Type": "Push", "Operands": ["dword ptr [esp]"] }] +FF35;[{ "Type": "Push", "Operands": ["dword ptr [ebp]"] }] +FF36;[{ "Type": "Push", "Operands": ["dword ptr [esi]"] }] +FF37;[{ "Type": "Push", "Operands": ["dword ptr [edi]"] }] + +# PUSH r/m32 (opcode FF /6) with memory operands and displacement +FF7010;[{ "Type": "Push", "Operands": ["dword ptr [eax+0x10]"] }] +FF7110;[{ "Type": "Push", "Operands": ["dword ptr [ecx+0x10]"] }] +FF7210;[{ "Type": "Push", "Operands": ["dword ptr [edx+0x10]"] }] +FF7310;[{ "Type": "Push", "Operands": ["dword ptr [ebx+0x10]"] }] +FF7410;[{ "Type": "Push", "Operands": ["dword ptr [esp+0x10]"] }] +FF7510;[{ "Type": "Push", "Operands": ["dword ptr [ebp+0x10]"] }] +FF7610;[{ "Type": "Push", "Operands": ["dword ptr [esi+0x10]"] }] +FF7710;[{ "Type": "Push", "Operands": ["dword ptr [edi+0x10]"] }] + +# PUSH r/m32 (opcode FF /6) with SIB byte +FF34C5;[{ "Type": "Push", "Operands": ["dword ptr [eax*8+ebp]"] }] +FF34CD;[{ "Type": "Push", "Operands": ["dword ptr [ecx*8+ebp]"] }] +FF34D5;[{ "Type": "Push", "Operands": ["dword ptr [edx*8+ebp]"] }] +FF34DD;[{ "Type": "Push", "Operands": ["dword ptr [ebx*8+ebp]"] }] + +# PUSH r/m32 (opcode FF /6) with direct memory operand +FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr [0x12345678]"] }] + +# PUSH r/m32 (opcode FF /6) with segment override prefixes +26FF7510;[{ "Type": "Push", "Operands": ["dword ptr es:[ebp+0x10]"] }] +2EFF7510;[{ "Type": "Push", "Operands": ["dword ptr cs:[ebp+0x10]"] }] +36FF7510;[{ "Type": "Push", "Operands": ["dword ptr ss:[ebp+0x10]"] }] +3EFF7510;[{ "Type": "Push", "Operands": ["dword ptr ds:[ebp+0x10]"] }] +64FF7510;[{ "Type": "Push", "Operands": ["dword ptr fs:[ebp+0x10]"] }] +65FF7510;[{ "Type": "Push", "Operands": ["dword ptr gs:[ebp+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/rcl_tests.csv b/X86DisassemblerTests/TestData/rcl_tests.csv new file mode 100644 index 0000000..dbea5f0 --- /dev/null +++ b/X86DisassemblerTests/TestData/rcl_tests.csv @@ -0,0 +1,32 @@ +# RCL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# RCL r/m8, 1 (opcode D0 /2) +D0D0;[{ "Type": "Rcl", "Operands": ["al", "0x01"] }] +D0D3;[{ "Type": "Rcl", "Operands": ["bl", "0x01"] }] + +# RCL r/m32, 1 (opcode D1 /2) +D1D0;[{ "Type": "Rcl", "Operands": ["eax", "0x01"] }] +D1D3;[{ "Type": "Rcl", "Operands": ["ebx", "0x01"] }] + +# RCL r/m8, CL (opcode D2 /2) +D2D0;[{ "Type": "Rcl", "Operands": ["al", "cl"] }] +D2D3;[{ "Type": "Rcl", "Operands": ["bl", "cl"] }] + +# RCL r/m32, CL (opcode D3 /2) +D3D0;[{ "Type": "Rcl", "Operands": ["eax", "cl"] }] +D3D3;[{ "Type": "Rcl", "Operands": ["ebx", "cl"] }] + +# RCL r/m8, imm8 (opcode C0 /2) +C0D005;[{ "Type": "Rcl", "Operands": ["al", "0x05"] }] +C0D305;[{ "Type": "Rcl", "Operands": ["bl", "0x05"] }] + +# RCL r/m32, imm8 (opcode C1 /2) +C1D005;[{ "Type": "Rcl", "Operands": ["eax", "0x05"] }] +C1D305;[{ "Type": "Rcl", "Operands": ["ebx", "0x05"] }] + +# RCL with memory operands +D0142510;[{ "Type": "Rcl", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D31425;[{ "Type": "Rcl", "Operands": ["dword ptr [eax]", "cl"] }] +C1142505;[{ "Type": "Rcl", "Operands": ["dword ptr [eax]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/rcr_tests.csv b/X86DisassemblerTests/TestData/rcr_tests.csv new file mode 100644 index 0000000..1544086 --- /dev/null +++ b/X86DisassemblerTests/TestData/rcr_tests.csv @@ -0,0 +1,32 @@ +# RCR instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# RCR r/m8, 1 (opcode D0 /3) +D0D8;[{ "Type": "Rcr", "Operands": ["al", "0x01"] }] +D0DB;[{ "Type": "Rcr", "Operands": ["bl", "0x01"] }] + +# RCR r/m32, 1 (opcode D1 /3) +D1D8;[{ "Type": "Rcr", "Operands": ["eax", "0x01"] }] +D1DB;[{ "Type": "Rcr", "Operands": ["ebx", "0x01"] }] + +# RCR r/m8, CL (opcode D2 /3) +D2D8;[{ "Type": "Rcr", "Operands": ["al", "cl"] }] +D2DB;[{ "Type": "Rcr", "Operands": ["bl", "cl"] }] + +# RCR r/m32, CL (opcode D3 /3) +D3D8;[{ "Type": "Rcr", "Operands": ["eax", "cl"] }] +D3DB;[{ "Type": "Rcr", "Operands": ["ebx", "cl"] }] + +# RCR r/m8, imm8 (opcode C0 /3) +C0D805;[{ "Type": "Rcr", "Operands": ["al", "0x05"] }] +C0DB05;[{ "Type": "Rcr", "Operands": ["bl", "0x05"] }] + +# RCR r/m32, imm8 (opcode C1 /3) +C1D805;[{ "Type": "Rcr", "Operands": ["eax", "0x05"] }] +C1DB05;[{ "Type": "Rcr", "Operands": ["ebx", "0x05"] }] + +# RCR with memory operands +D01C2510;[{ "Type": "Rcr", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D31C25;[{ "Type": "Rcr", "Operands": ["dword ptr [eax]", "cl"] }] +C11C2505;[{ "Type": "Rcr", "Operands": ["dword ptr [eax]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/ret_tests.csv b/X86DisassemblerTests/TestData/ret_tests.csv new file mode 100644 index 0000000..3875923 --- /dev/null +++ b/X86DisassemblerTests/TestData/ret_tests.csv @@ -0,0 +1,23 @@ +# RET instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# RET (opcode C3) - Near return to calling procedure +C3;[{ "Type": "Ret", "Operands": [] }] + +# RET imm16 (opcode C2) - Near return to calling procedure and pop imm16 bytes from stack +C20000;[{ "Type": "Ret", "Operands": ["0x0000"] }] +C20400;[{ "Type": "Ret", "Operands": ["0x0004"] }] +C20800;[{ "Type": "Ret", "Operands": ["0x0008"] }] +C21000;[{ "Type": "Ret", "Operands": ["0x0010"] }] +C2FFFF;[{ "Type": "Ret", "Operands": ["0xFFFF"] }] + +# RETF (opcode CB) - Far return to calling procedure +CB;[{ "Type": "Retf", "Operands": [] }] + +# RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack +CA0000;[{ "Type": "Retf", "Operands": ["0x0000"] }] +CA0400;[{ "Type": "Retf", "Operands": ["0x0004"] }] +CA0800;[{ "Type": "Retf", "Operands": ["0x0008"] }] +CA1000;[{ "Type": "Retf", "Operands": ["0x0010"] }] +CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }] diff --git a/X86DisassemblerTests/TestData/rol_tests.csv b/X86DisassemblerTests/TestData/rol_tests.csv new file mode 100644 index 0000000..22a2330 --- /dev/null +++ b/X86DisassemblerTests/TestData/rol_tests.csv @@ -0,0 +1,32 @@ +# ROL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# ROL r/m8, 1 (opcode D0 /0) +D0C0;[{ "Type": "Rol", "Operands": ["al", "0x01"] }] +D0C3;[{ "Type": "Rol", "Operands": ["bl", "0x01"] }] + +# ROL r/m32, 1 (opcode D1 /0) +D1C0;[{ "Type": "Rol", "Operands": ["eax", "0x01"] }] +D1C3;[{ "Type": "Rol", "Operands": ["ebx", "0x01"] }] + +# ROL r/m8, CL (opcode D2 /0) +D2C0;[{ "Type": "Rol", "Operands": ["al", "cl"] }] +D2C3;[{ "Type": "Rol", "Operands": ["bl", "cl"] }] + +# ROL r/m32, CL (opcode D3 /0) +D3C0;[{ "Type": "Rol", "Operands": ["eax", "cl"] }] +D3C3;[{ "Type": "Rol", "Operands": ["ebx", "cl"] }] + +# ROL r/m8, imm8 (opcode C0 /0) +C0C005;[{ "Type": "Rol", "Operands": ["al", "0x05"] }] +C0C305;[{ "Type": "Rol", "Operands": ["bl", "0x05"] }] + +# ROL r/m32, imm8 (opcode C1 /0) +C1C005;[{ "Type": "Rol", "Operands": ["eax", "0x05"] }] +C1C305;[{ "Type": "Rol", "Operands": ["ebx", "0x05"] }] + +# ROL with memory operands +D0042510;[{ "Type": "Rol", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D3042510;[{ "Type": "Rol", "Operands": ["dword ptr [eax+0x10]", "cl"] }] +C1042505;[{ "Type": "Rol", "Operands": ["dword ptr [eax+0x10]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/ror_tests.csv b/X86DisassemblerTests/TestData/ror_tests.csv new file mode 100644 index 0000000..134d037 --- /dev/null +++ b/X86DisassemblerTests/TestData/ror_tests.csv @@ -0,0 +1,32 @@ +# ROR instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# ROR r/m8, 1 (opcode D0 /1) +D0C8;[{ "Type": "Ror", "Operands": ["al", "0x01"] }] +D0CB;[{ "Type": "Ror", "Operands": ["bl", "0x01"] }] + +# ROR r/m32, 1 (opcode D1 /1) +D1C8;[{ "Type": "Ror", "Operands": ["eax", "0x01"] }] +D1CB;[{ "Type": "Ror", "Operands": ["ebx", "0x01"] }] + +# ROR r/m8, CL (opcode D2 /1) +D2C8;[{ "Type": "Ror", "Operands": ["al", "cl"] }] +D2CB;[{ "Type": "Ror", "Operands": ["bl", "cl"] }] + +# ROR r/m32, CL (opcode D3 /1) +D3C8;[{ "Type": "Ror", "Operands": ["eax", "cl"] }] +D3CB;[{ "Type": "Ror", "Operands": ["ebx", "cl"] }] + +# ROR r/m8, imm8 (opcode C0 /1) +C0C805;[{ "Type": "Ror", "Operands": ["al", "0x05"] }] +C0CB05;[{ "Type": "Ror", "Operands": ["bl", "0x05"] }] + +# ROR r/m32, imm8 (opcode C1 /1) +C1C805;[{ "Type": "Ror", "Operands": ["eax", "0x05"] }] +C1CB05;[{ "Type": "Ror", "Operands": ["ebx", "0x05"] }] + +# ROR with memory operands +D00C2510;[{ "Type": "Ror", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D30C2510;[{ "Type": "Ror", "Operands": ["dword ptr [eax+0x10]", "cl"] }] +C10C2505;[{ "Type": "Ror", "Operands": ["dword ptr [eax+0x10]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/sar_tests.csv b/X86DisassemblerTests/TestData/sar_tests.csv new file mode 100644 index 0000000..87b590c --- /dev/null +++ b/X86DisassemblerTests/TestData/sar_tests.csv @@ -0,0 +1,32 @@ +# SAR instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# SAR r/m8, 1 (opcode D0 /7) +D0F8;[{ "Type": "Sar", "Operands": ["al", "0x01"] }] +D0FB;[{ "Type": "Sar", "Operands": ["bl", "0x01"] }] + +# SAR r/m32, 1 (opcode D1 /7) +D1F8;[{ "Type": "Sar", "Operands": ["eax", "0x01"] }] +D1FB;[{ "Type": "Sar", "Operands": ["ebx", "0x01"] }] + +# SAR r/m8, CL (opcode D2 /7) +D2F8;[{ "Type": "Sar", "Operands": ["al", "cl"] }] +D2FB;[{ "Type": "Sar", "Operands": ["bl", "cl"] }] + +# SAR r/m32, CL (opcode D3 /7) +D3F8;[{ "Type": "Sar", "Operands": ["eax", "cl"] }] +D3FB;[{ "Type": "Sar", "Operands": ["ebx", "cl"] }] + +# SAR r/m8, imm8 (opcode C0 /7) +C0F805;[{ "Type": "Sar", "Operands": ["al", "0x05"] }] +C0FB05;[{ "Type": "Sar", "Operands": ["bl", "0x05"] }] + +# SAR r/m32, imm8 (opcode C1 /7) +C1F805;[{ "Type": "Sar", "Operands": ["eax", "0x05"] }] +C1FB05;[{ "Type": "Sar", "Operands": ["ebx", "0x05"] }] + +# SAR with memory operands +D03C2510;[{ "Type": "Sar", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D33C25;[{ "Type": "Sar", "Operands": ["dword ptr [eax]", "cl"] }] +C13C2505;[{ "Type": "Sar", "Operands": ["dword ptr [eax]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/sbb_tests.csv b/X86DisassemblerTests/TestData/sbb_tests.csv new file mode 100644 index 0000000..ab30f0a --- /dev/null +++ b/X86DisassemblerTests/TestData/sbb_tests.csv @@ -0,0 +1,25 @@ +# SBB instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# SBB r/m8, imm8 (opcode 80 /3) +80D842;[{ "Type": "Sbb", "Operands": ["al", "0x42"] }] + +# SBB r/m32, imm32 (opcode 81 /3) +81D878563412;[{ "Type": "Sbb", "Operands": ["eax", "0x12345678"] }] + +# SBB r/m32, imm8 (opcode 83 /3) +83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }] + +# SBB with memory operands +811C2578563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }] + +# SBB r/m32, r32 (opcode 19) +19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }] +19CA;[{ "Type": "Sbb", "Operands": ["edx", "ecx"] }] +194B10;[{ "Type": "Sbb", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] + +# SBB r32, r/m32 (opcode 1B) +1BD8;[{ "Type": "Sbb", "Operands": ["ebx", "eax"] }] +1BCA;[{ "Type": "Sbb", "Operands": ["ecx", "edx"] }] +1B4B10;[{ "Type": "Sbb", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestData/segment_override_tests.csv b/X86DisassemblerTests/TestData/segment_override_tests.csv index ceed94f..068228d 100644 --- a/X86DisassemblerTests/TestData/segment_override_tests.csv +++ b/X86DisassemblerTests/TestData/segment_override_tests.csv @@ -1,7 +1,61 @@ +# Segment override prefix tests +# Format: RawBytes;Instructions RawBytes;Instructions -26FF7510;[{ "Mnemonic": "push", "Operands": "dword ptr es:[ebp+0x10]" }] -2EFF7510;[{ "Mnemonic": "push", "Operands": "dword ptr cs:[ebp+0x10]" }] -36FF7510;[{ "Mnemonic": "push", "Operands": "dword ptr ss:[ebp+0x10]" }] -3EFF7510;[{ "Mnemonic": "push", "Operands": "dword ptr ds:[ebp+0x10]" }] -64FF7510;[{ "Mnemonic": "push", "Operands": "dword ptr fs:[ebp+0x10]" }] -65FF7510;[{ "Mnemonic": "push", "Operands": "dword ptr gs:[ebp+0x10]" }] + +# Basic segment override tests with PUSH instruction +26FF7510;[{ "Type": "Push", "Operands": ["dword ptr es:[ebp+0x10]"] }] +2EFF7510;[{ "Type": "Push", "Operands": ["dword ptr cs:[ebp+0x10]"] }] +36FF7510;[{ "Type": "Push", "Operands": ["dword ptr ss:[ebp+0x10]"] }] +3EFF7510;[{ "Type": "Push", "Operands": ["dword ptr ds:[ebp+0x10]"] }] +64FF7510;[{ "Type": "Push", "Operands": ["dword ptr fs:[ebp+0x10]"] }] +65FF7510;[{ "Type": "Push", "Operands": ["dword ptr gs:[ebp+0x10]"] }] + +# Segment override with different instructions + +# MOV instructions with segment overrides +26890D78563412;[{ "Type": "Mov", "Operands": ["dword ptr es:[0x12345678]", "ecx"] }] +2E8B0D78563412;[{ "Type": "Mov", "Operands": ["ecx", "dword ptr cs:[0x12345678]"] }] +368B4D10;[{ "Type": "Mov", "Operands": ["ecx", "dword ptr ss:[ebp+0x10]"] }] +3E8B4D10;[{ "Type": "Mov", "Operands": ["ecx", "dword ptr ds:[ebp+0x10]"] }] +64A178563412;[{ "Type": "Mov", "Operands": ["eax", "dword ptr fs:[0x12345678]"] }] +65A378563412;[{ "Type": "Mov", "Operands": ["dword ptr gs:[0x12345678]", "eax"] }] + +# ADD instructions with segment overrides +26034B10;[{ "Type": "Add", "Operands": ["ecx", "dword ptr es:[ebx+0x10]"] }] +2E014B10;[{ "Type": "Add", "Operands": ["dword ptr cs:[ebx+0x10]", "ecx"] }] +36034B10;[{ "Type": "Add", "Operands": ["ecx", "dword ptr ss:[ebx+0x10]"] }] +3E014B10;[{ "Type": "Add", "Operands": ["dword ptr ds:[ebx+0x10]", "ecx"] }] +64034B10;[{ "Type": "Add", "Operands": ["ecx", "dword ptr fs:[ebx+0x10]"] }] +65014B10;[{ "Type": "Add", "Operands": ["dword ptr gs:[ebx+0x10]", "ecx"] }] + +# SUB instructions with segment overrides +262B4B10;[{ "Type": "Sub", "Operands": ["ecx", "dword ptr es:[ebx+0x10]"] }] +2E294B10;[{ "Type": "Sub", "Operands": ["dword ptr cs:[ebx+0x10]", "ecx"] }] +362B4B10;[{ "Type": "Sub", "Operands": ["ecx", "dword ptr ss:[ebx+0x10]"] }] +3E294B10;[{ "Type": "Sub", "Operands": ["dword ptr ds:[ebx+0x10]", "ecx"] }] +642B4B10;[{ "Type": "Sub", "Operands": ["ecx", "dword ptr fs:[ebx+0x10]"] }] +65294B10;[{ "Type": "Sub", "Operands": ["dword ptr gs:[ebx+0x10]", "ecx"] }] + +# XOR instructions with segment overrides +26334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr es:[ebx+0x10]"] }] +2E314B10;[{ "Type": "Xor", "Operands": ["dword ptr cs:[ebx+0x10]", "ecx"] }] +36334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr ss:[ebx+0x10]"] }] +3E314B10;[{ "Type": "Xor", "Operands": ["dword ptr ds:[ebx+0x10]", "ecx"] }] +64334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr fs:[ebx+0x10]"] }] +65314B10;[{ "Type": "Xor", "Operands": ["dword ptr gs:[ebx+0x10]", "ecx"] }] + +# Complex addressing modes with segment overrides +26891C8D78563412;[{ "Type": "Mov", "Operands": ["dword ptr es:[ebp+ecx*4+0x12345678]", "ebx"] }] +2E8B1C8D78563412;[{ "Type": "Mov", "Operands": ["ebx", "dword ptr cs:[ebp+ecx*4+0x12345678]"] }] +36891C8D78563412;[{ "Type": "Mov", "Operands": ["dword ptr ss:[ebp+ecx*4+0x12345678]", "ebx"] }] +3E8B1C8D78563412;[{ "Type": "Mov", "Operands": ["ebx", "dword ptr ds:[ebp+ecx*4+0x12345678]"] }] +64891C8D78563412;[{ "Type": "Mov", "Operands": ["dword ptr fs:[ebp+ecx*4+0x12345678]", "ebx"] }] +658B1C8D78563412;[{ "Type": "Mov", "Operands": ["ebx", "dword ptr gs:[ebp+ecx*4+0x12345678]"] }] + +# Direct memory addressing with segment overrides +26FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr es:[0x12345678]"] }] +2EFF3578563412;[{ "Type": "Push", "Operands": ["dword ptr cs:[0x12345678]"] }] +36FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr ss:[0x12345678]"] }] +3EFF3578563412;[{ "Type": "Push", "Operands": ["dword ptr ds:[0x12345678]"] }] +64FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr fs:[0x12345678]"] }] +65FF3578563412;[{ "Type": "Push", "Operands": ["dword ptr gs:[0x12345678]"] }] diff --git a/X86DisassemblerTests/TestData/shl_tests.csv b/X86DisassemblerTests/TestData/shl_tests.csv new file mode 100644 index 0000000..f3dd672 --- /dev/null +++ b/X86DisassemblerTests/TestData/shl_tests.csv @@ -0,0 +1,32 @@ +# SHL instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# SHL r/m8, 1 (opcode D0 /4) +D0E0;[{ "Type": "Shl", "Operands": ["al", "0x01"] }] +D0E3;[{ "Type": "Shl", "Operands": ["bl", "0x01"] }] + +# SHL r/m32, 1 (opcode D1 /4) +D1E0;[{ "Type": "Shl", "Operands": ["eax", "0x01"] }] +D1E3;[{ "Type": "Shl", "Operands": ["ebx", "0x01"] }] + +# SHL r/m8, CL (opcode D2 /4) +D2E0;[{ "Type": "Shl", "Operands": ["al", "cl"] }] +D2E3;[{ "Type": "Shl", "Operands": ["bl", "cl"] }] + +# SHL r/m32, CL (opcode D3 /4) +D3E0;[{ "Type": "Shl", "Operands": ["eax", "cl"] }] +D3E3;[{ "Type": "Shl", "Operands": ["ebx", "cl"] }] + +# SHL r/m8, imm8 (opcode C0 /4) +C0E005;[{ "Type": "Shl", "Operands": ["al", "0x05"] }] +C0E305;[{ "Type": "Shl", "Operands": ["bl", "0x05"] }] + +# SHL r/m32, imm8 (opcode C1 /4) +C1E005;[{ "Type": "Shl", "Operands": ["eax", "0x05"] }] +C1E305;[{ "Type": "Shl", "Operands": ["ebx", "0x05"] }] + +# SHL with memory operands +D0242510000000;[{ "Type": "Shl", "Operands": ["byte ptr [0x10]", "0x01"] }] +D32425;[{ "Type": "Shl", "Operands": ["dword ptr [eax]", "cl"] }] +C1242510000005;[{ "Type": "Shl", "Operands": ["dword ptr [0x10]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/shr_tests.csv b/X86DisassemblerTests/TestData/shr_tests.csv new file mode 100644 index 0000000..a220e7b --- /dev/null +++ b/X86DisassemblerTests/TestData/shr_tests.csv @@ -0,0 +1,32 @@ +# SHR instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# SHR r/m8, 1 (opcode D0 /5) +D0E8;[{ "Type": "Shr", "Operands": ["al", "0x01"] }] +D0EB;[{ "Type": "Shr", "Operands": ["bl", "0x01"] }] + +# SHR r/m32, 1 (opcode D1 /5) +D1E8;[{ "Type": "Shr", "Operands": ["eax", "0x01"] }] +D1EB;[{ "Type": "Shr", "Operands": ["ebx", "0x01"] }] + +# SHR r/m8, CL (opcode D2 /5) +D2E8;[{ "Type": "Shr", "Operands": ["al", "cl"] }] +D2EB;[{ "Type": "Shr", "Operands": ["bl", "cl"] }] + +# SHR r/m32, CL (opcode D3 /5) +D3E8;[{ "Type": "Shr", "Operands": ["eax", "cl"] }] +D3EB;[{ "Type": "Shr", "Operands": ["ebx", "cl"] }] + +# SHR r/m8, imm8 (opcode C0 /5) +C0E805;[{ "Type": "Shr", "Operands": ["al", "0x05"] }] +C0EB05;[{ "Type": "Shr", "Operands": ["bl", "0x05"] }] + +# SHR r/m32, imm8 (opcode C1 /5) +C1E805;[{ "Type": "Shr", "Operands": ["eax", "0x05"] }] +C1EB05;[{ "Type": "Shr", "Operands": ["ebx", "0x05"] }] + +# SHR with memory operands +D02C2510;[{ "Type": "Shr", "Operands": ["byte ptr [eax+0x10]", "0x01"] }] +D32C25;[{ "Type": "Shr", "Operands": ["dword ptr [eax]", "cl"] }] +C12C2505;[{ "Type": "Shr", "Operands": ["dword ptr [eax]", "0x05"] }] diff --git a/X86DisassemblerTests/TestData/stack_tests.csv b/X86DisassemblerTests/TestData/stack_tests.csv new file mode 100644 index 0000000..7f4b94f --- /dev/null +++ b/X86DisassemblerTests/TestData/stack_tests.csv @@ -0,0 +1,24 @@ +# Stack manipulation instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# PUSHA/PUSHAD - Push All General-Purpose Registers +60;[{ "Type": "Pushad", "Operands": [] }] + +# POPA/POPAD - Pop All General-Purpose Registers +61;[{ "Type": "Popad", "Operands": [] }] + +# PUSHF/PUSHFD - Push EFLAGS Register onto the Stack +9C;[{ "Type": "Pushfd", "Operands": [] }] + +# POPF/POPFD - Pop Stack into EFLAGS Register +9D;[{ "Type": "Popfd", "Operands": [] }] + +# ENTER - Make Stack Frame for Procedure Parameters +C8000000;[{ "Type": "Enter", "Operands": ["0x0000", "0x00"] }] +C8100000;[{ "Type": "Enter", "Operands": ["0x0010", "0x00"] }] +C8000001;[{ "Type": "Enter", "Operands": ["0x0000", "0x01"] }] +C8100001;[{ "Type": "Enter", "Operands": ["0x0010", "0x01"] }] + +# LEAVE - High Level Procedure Exit +C9;[{ "Type": "Leave", "Operands": [] }] diff --git a/X86DisassemblerTests/TestData/string_tests.csv b/X86DisassemblerTests/TestData/string_tests.csv new file mode 100644 index 0000000..6a4c435 --- /dev/null +++ b/X86DisassemblerTests/TestData/string_tests.csv @@ -0,0 +1,52 @@ +# String instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# MOVS - Move string +A4;[{ "Type": "MovsB", "Operands": [] }] +A5;[{ "Type": "MovsD", "Operands": [] }] +66A5;[{ "Type": "MovsW", "Operands": [] }] + +# CMPS - Compare string +A6;[{ "Type": "CmpsB", "Operands": [] }] +A7;[{ "Type": "CmpsD", "Operands": [] }] +66A7;[{ "Type": "CmpsW", "Operands": [] }] + +# SCAS - Scan string +AE;[{ "Type": "ScasB", "Operands": [] }] +AF;[{ "Type": "ScasD", "Operands": [] }] +66AF;[{ "Type": "ScasW", "Operands": [] }] + +# LODS - Load string +AC;[{ "Type": "LodsB", "Operands": [] }] +AD;[{ "Type": "LodsD", "Operands": [] }] +66AD;[{ "Type": "LodsW", "Operands": [] }] + +# STOS - Store string +AA;[{ "Type": "StosB", "Operands": [] }] +AB;[{ "Type": "StosD", "Operands": [] }] +66AB;[{ "Type": "StosW", "Operands": [] }] + +# REP prefix with string instructions +F3A4;[{ "Type": "RepMovsB", "Operands": [] }] +F3A5;[{ "Type": "RepMovsD", "Operands": [] }] +F366A5;[{ "Type": "RepMovsW", "Operands": [] }] +F3AA;[{ "Type": "RepStosB", "Operands": [] }] +F3AB;[{ "Type": "RepStosD", "Operands": [] }] +F366AB;[{ "Type": "RepStosW", "Operands": [] }] + +# REPE/REPZ prefix with string instructions +F3A6;[{ "Type": "RepeCmpsB", "Operands": [] }] +F3A7;[{ "Type": "RepeCmpsD", "Operands": [] }] +F366A7;[{ "Type": "RepeCmpsW", "Operands": [] }] +F3AE;[{ "Type": "RepScasB", "Operands": [] }] +F3AF;[{ "Type": "RepScasD", "Operands": [] }] +F366AF;[{ "Type": "RepScasW", "Operands": [] }] + +# REPNE/REPNZ prefix with string instructions +F2A6;[{ "Type": "RepneCmpsB", "Operands": [] }] +F2A7;[{ "Type": "RepneCmpsD", "Operands": [] }] +F266A7;[{ "Type": "RepneCmpsW", "Operands": [] }] +F2AE;[{ "Type": "RepneScasB", "Operands": [] }] +F2AF;[{ "Type": "RepneScasD", "Operands": [] }] +F266AF;[{ "Type": "RepneScasW", "Operands": [] }] diff --git a/X86DisassemblerTests/TestData/sub_tests.csv b/X86DisassemblerTests/TestData/sub_tests.csv index e48591f..9a85631 100644 --- a/X86DisassemblerTests/TestData/sub_tests.csv +++ b/X86DisassemblerTests/TestData/sub_tests.csv @@ -3,87 +3,115 @@ RawBytes;Instructions # Register-to-register SUB (32-bit) -29D8;[{ "Mnemonic": "sub", "Operands": "eax, ebx" }] +29D8;[{ "Type": "Sub", "Operands": ["eax", "ebx"] }] # Register-to-memory SUB (32-bit) -294B10;[{ "Mnemonic": "sub", "Operands": "dword ptr [ebx+0x10], ecx" }] +294B10;[{ "Type": "Sub", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] # Memory-to-register SUB (32-bit) -2BD8;[{ "Mnemonic": "sub", "Operands": "ebx, eax" }] -2B4B10;[{ "Mnemonic": "sub", "Operands": "ecx, dword ptr [ebx+0x10]" }] +2BD8;[{ "Type": "Sub", "Operands": ["ebx", "eax"] }] +2B4B10;[{ "Type": "Sub", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] # Immediate-to-register SUB (32-bit immediate) -81E878563412;[{ "Mnemonic": "sub", "Operands": "eax, 0x12345678" }] +81E878563412;[{ "Type": "Sub", "Operands": ["eax", "0x12345678"] }] # Immediate-to-memory SUB (32-bit immediate) -816B1078563412;[{ "Mnemonic": "sub", "Operands": "dword ptr [ebx+0x10], 0x12345678" }] +816B1078563412;[{ "Type": "Sub", "Operands": ["dword ptr [ebx+0x10]", "0x12345678"] }] # Small immediate SUB (8-bit immediate to 32-bit register) -83E842;[{ "Mnemonic": "sub", "Operands": "eax, 0x42" }] +83E842;[{ "Type": "Sub", "Operands": ["eax", "0x42"] }] # Sign-extended immediate SUB (8-bit immediate sign-extended to 32-bit) -83E8F0;[{ "Mnemonic": "sub", "Operands": "eax, 0xFFFFFFF0" }] +83E8F0;[{ "Type": "Sub", "Operands": ["eax", "0xFFFFFFF0"] }] # 8-bit register operations # SUB r/m8, r8 (opcode 28) -28C3;[{ "Mnemonic": "sub", "Operands": "bl, al" }] +28C3;[{ "Type": "Sub", "Operands": ["bl", "al"] }] # SUB r8, r/m8 (opcode 2A) -2AC3;[{ "Mnemonic": "sub", "Operands": "al, bl" }] +2AC3;[{ "Type": "Sub", "Operands": ["al", "bl"] }] # SUB AL, imm8 (opcode 2C) -2C42;[{ "Mnemonic": "sub", "Operands": "al, 0x42" }] +2C42;[{ "Type": "Sub", "Operands": ["al", "0x42"] }] # SUB r/m8, imm8 (opcode 80 /5) -80EB42;[{ "Mnemonic": "sub", "Operands": "bl, 0x42" }] +80EB42;[{ "Type": "Sub", "Operands": ["bl", "0x42"] }] # 16-bit register operations with operand size prefix (0x66) -# Note: The disassembler currently outputs 32-bit register names even with 0x66 prefix # SUB r/m16, r16 (opcode 29 with 0x66 prefix) -6629D8;[{ "Mnemonic": "sub", "Operands": "eax, ebx" }] +6629D8;[{ "Type": "Sub", "Operands": ["eax", "ebx"] }] # SUB r16, r/m16 (opcode 2B with 0x66 prefix) -662BD8;[{ "Mnemonic": "sub", "Operands": "ebx, eax" }] +662BD8;[{ "Type": "Sub", "Operands": ["ebx", "eax"] }] # SUB AX, imm16 (opcode 2D with 0x66 prefix) -662D3412;[{ "Mnemonic": "sub", "Operands": "eax, 0x1234" }] +662D3412;[{ "Type": "Sub", "Operands": ["eax", "0x1234"] }] # SUB r/m16, imm8 (opcode 83 /5 with 0x66 prefix and sign extension) -6683EB42;[{ "Mnemonic": "sub", "Operands": "ebx, 0x42" }] +6683EB42;[{ "Type": "Sub", "Operands": ["ebx", "0x42"] }] + +# SUB r/m16, imm16 (opcode 81 /5 with 0x66 prefix) +6681EB3412;[{ "Type": "Sub", "Operands": ["ebx", "0x1234"] }] # Additional test cases for more complex addressing modes # SUB with SIB byte addressing (Scale-Index-Base) # SUB [eax+ecx*4], edx (opcode 29) -291488;[{ "Mnemonic": "sub", "Operands": "dword ptr [eax+ecx*4], edx" }] +291488;[{ "Type": "Sub", "Operands": ["dword ptr [eax+ecx*4]", "edx"] }] # SUB edx, [eax+ecx*4] (opcode 2B) -2B1488;[{ "Mnemonic": "sub", "Operands": "edx, dword ptr [eax+ecx*4]" }] +2B1488;[{ "Type": "Sub", "Operands": ["edx", "dword ptr [eax+ecx*4]"] }] # SUB with displacement-only addressing # SUB [0x12345678], eax (opcode 29) -290578563412;[{ "Mnemonic": "sub", "Operands": "dword ptr [0x12345678], eax" }] +290578563412;[{ "Type": "Sub", "Operands": ["dword ptr [0x12345678]", "eax"] }] # SUB with segment override prefixes # SUB fs:[ebx+0x10], ecx (opcode 29 with FS override) -64294B10;[{ "Mnemonic": "sub", "Operands": "dword ptr fs:[ebx+0x10], ecx" }] +64294B10;[{ "Type": "Sub", "Operands": ["dword ptr fs:[ebx+0x10]", "ecx"] }] # SUB ecx, gs:[ebx+0x10] (opcode 2B with GS override) -652B4B10;[{ "Mnemonic": "sub", "Operands": "ecx, dword ptr gs:[ebx+0x10]" }] +652B4B10;[{ "Type": "Sub", "Operands": ["ecx", "dword ptr gs:[ebx+0x10]"] }] # SUB with complex addressing mode: base + index + scale + displacement # SUB [eax+ecx*4+0x12345678], edx (opcode 29) -29948878563412;[{ "Mnemonic": "sub", "Operands": "dword ptr [eax+ecx*4+0x12345678], edx" }] +29948878563412;[{ "Type": "Sub", "Operands": ["dword ptr [eax+ecx*4+0x12345678]", "edx"] }] # Edge cases for immediate values # SUB eax, 0x0 (opcode 83 /5 with zero immediate) -83E800;[{ "Mnemonic": "sub", "Operands": "eax, 0x00" }] +83E800;[{ "Type": "Sub", "Operands": ["eax", "0x00"] }] # SUB al, 0xFF (opcode 2C with max 8-bit immediate) -2CFF;[{ "Mnemonic": "sub", "Operands": "al, 0xFF" }] +2CFF;[{ "Type": "Sub", "Operands": ["al", "0xFF"] }] # SUB eax, 0xFFFFFFFF (opcode 81 /5 with max 32-bit immediate) -81E8FFFFFFFF;[{ "Mnemonic": "sub", "Operands": "eax, 0xFFFFFFFF" }] +81E8FFFFFFFF;[{ "Type": "Sub", "Operands": ["eax", "0xFFFFFFFF"] }] # SUB with negative immediate value (sign-extended) -83E8FF;[{ "Mnemonic": "sub", "Operands": "eax, 0xFFFFFFFF" }] +83E8FF;[{ "Type": "Sub", "Operands": ["eax", "0xFFFFFFFF"] }] + +# Additional tests for SubImmFromRm32Handler +# SUB r/m32, imm32 (opcode 81 /5) with various registers +81E978563412;[{ "Type": "Sub", "Operands": ["ecx", "0x12345678"] }] +81EA78563412;[{ "Type": "Sub", "Operands": ["edx", "0x12345678"] }] +81EB78563412;[{ "Type": "Sub", "Operands": ["ebx", "0x12345678"] }] +81EC78563412;[{ "Type": "Sub", "Operands": ["esp", "0x12345678"] }] +81ED78563412;[{ "Type": "Sub", "Operands": ["ebp", "0x12345678"] }] +81EE78563412;[{ "Type": "Sub", "Operands": ["esi", "0x12345678"] }] +81EF78563412;[{ "Type": "Sub", "Operands": ["edi", "0x12345678"] }] + +# SUB r/m32, imm32 (opcode 81 /5) with memory operands +818D10000000FFFFFFFF;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFFFF"] }] + +# Additional tests for SubImmFromRm32SignExtendedHandler +# SUB r/m32, imm8 (opcode 83 /5) with sign extension +83E9FF;[{ "Type": "Sub", "Operands": ["ecx", "0xFFFFFFFF"] }] +83EAFF;[{ "Type": "Sub", "Operands": ["edx", "0xFFFFFFFF"] }] +83EBFF;[{ "Type": "Sub", "Operands": ["ebx", "0xFFFFFFFF"] }] +83ECFF;[{ "Type": "Sub", "Operands": ["esp", "0xFFFFFFFF"] }] +83EDFF;[{ "Type": "Sub", "Operands": ["ebp", "0xFFFFFFFF"] }] +83EEFF;[{ "Type": "Sub", "Operands": ["esi", "0xFFFFFFFF"] }] +83EFFF;[{ "Type": "Sub", "Operands": ["edi", "0xFFFFFFFF"] }] + +# SUB r/m32, imm8 (opcode 83 /5) with memory operands and sign extension +838D1000000080;[{ "Type": "Sub", "Operands": ["dword ptr [ebp+0x10]", "0xFFFFFF80"] }] diff --git a/X86DisassemblerTests/TestData/test_tests.csv b/X86DisassemblerTests/TestData/test_tests.csv new file mode 100644 index 0000000..d51f957 --- /dev/null +++ b/X86DisassemblerTests/TestData/test_tests.csv @@ -0,0 +1,24 @@ +# TEST instruction tests +# Format: RawBytes;Instructions +RawBytes;Instructions + +# TEST r/m8, imm8 (opcode F6 /0) +F6C042;[{ "Type": "Test", "Operands": ["al", "0x42"] }] +F6C342;[{ "Type": "Test", "Operands": ["bl", "0x42"] }] + +# TEST r/m32, imm32 (opcode F7 /0) +F7C078563412;[{ "Type": "Test", "Operands": ["eax", "0x12345678"] }] +F7C378563412;[{ "Type": "Test", "Operands": ["ebx", "0x12345678"] }] + +# TEST r/m8, r8 (opcode 84) +84C3;[{ "Type": "Test", "Operands": ["bl", "al"] }] +84D9;[{ "Type": "Test", "Operands": ["cl", "bl"] }] + +# TEST r/m32, r32 (opcode 85) +85C3;[{ "Type": "Test", "Operands": ["ebx", "eax"] }] +85D9;[{ "Type": "Test", "Operands": ["ecx", "ebx"] }] + +# TEST with memory operands +F6042542;[{ "Type": "Test", "Operands": ["byte ptr [eax]", "0x42"] }] +F7042578563412;[{ "Type": "Test", "Operands": ["dword ptr [eax]", "0x12345678"] }] +85042510;[{ "Type": "Test", "Operands": ["dword ptr [eax+0x10]", "eax"] }] diff --git a/X86DisassemblerTests/TestData/xchg_tests.csv b/X86DisassemblerTests/TestData/xchg_tests.csv index 085b344..8ae980a 100644 --- a/X86DisassemblerTests/TestData/xchg_tests.csv +++ b/X86DisassemblerTests/TestData/xchg_tests.csv @@ -1,8 +1,36 @@ +# XCHG instruction tests +# Format: RawBytes;Instructions RawBytes;Instructions -91;[{ "Mnemonic": "xchg", "Operands": "eax, ecx" }] -92;[{ "Mnemonic": "xchg", "Operands": "eax, edx" }] -93;[{ "Mnemonic": "xchg", "Operands": "eax, ebx" }] -94;[{ "Mnemonic": "xchg", "Operands": "eax, esp" }] -95;[{ "Mnemonic": "xchg", "Operands": "eax, ebp" }] -96;[{ "Mnemonic": "xchg", "Operands": "eax, esi" }] -97;[{ "Mnemonic": "xchg", "Operands": "eax, edi" }] + +# XCHG EAX, reg32 (opcodes 90-97) +90;[{ "Type": "Nop", "Operands": [] }] +91;[{ "Type": "Xchg", "Operands": ["eax", "ecx"] }] +92;[{ "Type": "Xchg", "Operands": ["eax", "edx"] }] +93;[{ "Type": "Xchg", "Operands": ["eax", "ebx"] }] +94;[{ "Type": "Xchg", "Operands": ["eax", "esp"] }] +95;[{ "Type": "Xchg", "Operands": ["eax", "ebp"] }] +96;[{ "Type": "Xchg", "Operands": ["eax", "esi"] }] +97;[{ "Type": "Xchg", "Operands": ["eax", "edi"] }] + +# XCHG reg32, r/m32 (opcode 87) +87D9;[{ "Type": "Xchg", "Operands": ["ecx", "ebx"] }] +87CA;[{ "Type": "Xchg", "Operands": ["edx", "ecx"] }] + +# XCHG r/m32, reg32 (opcode 87) - memory operands +874B10;[{ "Type": "Xchg", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] +8711;[{ "Type": "Xchg", "Operands": ["edx", "dword ptr [ecx]"] }] +8713;[{ "Type": "Xchg", "Operands": ["edx", "dword ptr [ebx]"] }] + +# XCHG with 16-bit operand size prefix +6687D9;[{ "Type": "Xchg", "Operands": ["ecx", "ebx"] }] +6691;[{ "Type": "Xchg", "Operands": ["eax", "ecx"] }] + +# XCHG with 8-bit registers (opcode 86) +86D9;[{ "Type": "Xchg", "Operands": ["cl", "bl"] }] +86C3;[{ "Type": "Xchg", "Operands": ["al", "bl"] }] +86C1;[{ "Type": "Xchg", "Operands": ["al", "cl"] }] +86D3;[{ "Type": "Xchg", "Operands": ["dl", "bl"] }] + +# XCHG r/m8, reg8 (opcode 86) - memory operands +8601;[{ "Type": "Xchg", "Operands": ["al", "byte ptr [ecx]"] }] +8603;[{ "Type": "Xchg", "Operands": ["al", "byte ptr [ebx]"] }] diff --git a/X86DisassemblerTests/TestData/xor_tests.csv b/X86DisassemblerTests/TestData/xor_tests.csv index b00c0bc..9650560 100644 --- a/X86DisassemblerTests/TestData/xor_tests.csv +++ b/X86DisassemblerTests/TestData/xor_tests.csv @@ -3,122 +3,122 @@ RawBytes;Instructions # Register-to-register XOR (32-bit) -31D8;[{ "Mnemonic": "xor", "Operands": "eax, ebx" }] +31D8;[{ "Type": "Xor", "Operands": ["eax", "ebx"] }] # Register-to-memory XOR (32-bit) -314B10;[{ "Mnemonic": "xor", "Operands": "dword ptr [ebx+0x10], ecx" }] +314B10;[{ "Type": "Xor", "Operands": ["dword ptr [ebx+0x10]", "ecx"] }] # Memory-to-register XOR (32-bit) -33D8;[{ "Mnemonic": "xor", "Operands": "ebx, eax" }] -334B10;[{ "Mnemonic": "xor", "Operands": "ecx, dword ptr [ebx+0x10]" }] +33D8;[{ "Type": "Xor", "Operands": ["ebx", "eax"] }] +334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr [ebx+0x10]"] }] # Immediate-to-register XOR (32-bit immediate) -81F078563412;[{ "Mnemonic": "xor", "Operands": "eax, 0x12345678" }] +81F078563412;[{ "Type": "Xor", "Operands": ["eax", "0x12345678"] }] # Immediate-to-memory XOR (32-bit immediate) -81701078563412;[{ "Mnemonic": "xor", "Operands": "dword ptr [eax+0x10], 0x12345678" }] +81701078563412;[{ "Type": "Xor", "Operands": ["dword ptr [eax+0x10]", "0x12345678"] }] # Small immediate XOR (8-bit immediate to 32-bit register with sign extension) -83F042;[{ "Mnemonic": "xor", "Operands": "eax, 0x42" }] +83F042;[{ "Type": "Xor", "Operands": ["eax", "0x42"] }] # Sign-extended immediate XOR (8-bit immediate sign-extended to 32-bit) -83F0F0;[{ "Mnemonic": "xor", "Operands": "eax, 0xFFFFFFF0" }] +83F0F0;[{ "Type": "Xor", "Operands": ["eax", "0xFFFFFFF0"] }] # XOR AL, imm8 (opcode 0x34) -3442;[{ "Mnemonic": "xor", "Operands": "al, 0x42" }] +3442;[{ "Type": "Xor", "Operands": ["al", "0x42"] }] # XOR EAX, imm32 (opcode 0x35) -3578563412;[{ "Mnemonic": "xor", "Operands": "eax, 0x12345678" }] +3578563412;[{ "Type": "Xor", "Operands": ["eax", "0x12345678"] }] # XOR with SIB byte addressing (Scale-Index-Base) # XOR [eax+ecx*4], edx (opcode 0x31) -311488;[{ "Mnemonic": "xor", "Operands": "dword ptr [eax+ecx*4], edx" }] +311488;[{ "Type": "Xor", "Operands": ["dword ptr [eax+ecx*4]", "edx"] }] # XOR edx, [eax+ecx*4] (opcode 0x33) -331488;[{ "Mnemonic": "xor", "Operands": "edx, dword ptr [eax+ecx*4]" }] +331488;[{ "Type": "Xor", "Operands": ["edx", "dword ptr [eax+ecx*4]"] }] # XOR with displacement-only addressing # XOR [0x12345678], eax (opcode 0x31) -310578563412;[{ "Mnemonic": "xor", "Operands": "dword ptr [0x12345678], eax" }] +310578563412;[{ "Type": "Xor", "Operands": ["dword ptr [0x12345678]", "eax"] }] # XOR with segment override prefixes # XOR fs:[ebx+0x10], ecx (opcode 0x31 with FS override) -64314B10;[{ "Mnemonic": "xor", "Operands": "dword ptr fs:[ebx+0x10], ecx" }] +64314B10;[{ "Type": "Xor", "Operands": ["dword ptr fs:[ebx+0x10]", "ecx"] }] # XOR ecx, gs:[ebx+0x10] (opcode 0x33 with GS override) -65334B10;[{ "Mnemonic": "xor", "Operands": "ecx, dword ptr gs:[ebx+0x10]" }] +65334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr gs:[ebx+0x10]"] }] # XOR with complex addressing mode: base + index + scale + displacement # XOR [eax+ecx*4+0x12345678], edx (opcode 0x31) -31948878563412;[{ "Mnemonic": "xor", "Operands": "dword ptr [eax+ecx*4+0x12345678], edx" }] +31948878563412;[{ "Type": "Xor", "Operands": ["dword ptr [eax+ecx*4+0x12345678]", "edx"] }] # Edge cases for immediate values # XOR eax, 0x0 (opcode 0x83 /6 with zero immediate) -83F000;[{ "Mnemonic": "xor", "Operands": "eax, 0x00" }] +83F000;[{ "Type": "Xor", "Operands": ["eax", "0x00"] }] # XOR al, 0xFF (opcode 0x34 with max 8-bit immediate) -34FF;[{ "Mnemonic": "xor", "Operands": "al, 0xFF" }] +34FF;[{ "Type": "Xor", "Operands": ["al", "0xFF"] }] # XOR eax, 0xFFFFFFFF (opcode 0x81 /6 with max 32-bit immediate) -81F0FFFFFFFF;[{ "Mnemonic": "xor", "Operands": "eax, 0xFFFFFFFF" }] +81F0FFFFFFFF;[{ "Type": "Xor", "Operands": ["eax", "0xFFFFFFFF"] }] # XOR with negative immediate value (sign-extended) -83F0FF;[{ "Mnemonic": "xor", "Operands": "eax, 0xFFFFFFFF" }] +83F0FF;[{ "Type": "Xor", "Operands": ["eax", "0xFFFFFFFF"] }] # 16-bit XOR tests (with 0x66 prefix) # XOR AX, imm16 (opcode 0x35 with 0x66 prefix) -6635ABCD;[{ "Mnemonic": "xor", "Operands": "ax, 0xCDAB" }] +6635ABCD;[{ "Type": "Xor", "Operands": ["ax", "0xCDAB"] }] # XOR r16, r/m16 (opcode 0x33 with 0x66 prefix) -6633D8;[{ "Mnemonic": "xor", "Operands": "bx, ax" }] -6633C9;[{ "Mnemonic": "xor", "Operands": "cx, cx" }] +6633D8;[{ "Type": "Xor", "Operands": ["bx", "ax"] }] +6633C9;[{ "Type": "Xor", "Operands": ["cx", "cx"] }] # XOR r/m16, r16 (opcode 0x31 with 0x66 prefix) -6631D8;[{ "Mnemonic": "xor", "Operands": "ax, bx" }] -6631C9;[{ "Mnemonic": "xor", "Operands": "cx, cx" }] +6631D8;[{ "Type": "Xor", "Operands": ["ax", "bx"] }] +6631C9;[{ "Type": "Xor", "Operands": ["cx", "cx"] }] # XOR r/m16, imm16 (opcode 0x81 /6 with 0x66 prefix) -6681F0ABCD;[{ "Mnemonic": "xor", "Operands": "ax, 0xCDAB" }] +6681F0ABCD;[{ "Type": "Xor", "Operands": ["ax", "0xCDAB"] }] # XOR r/m16, imm8 (sign-extended) (opcode 0x83 /6 with 0x66 prefix) -6683F042;[{ "Mnemonic": "xor", "Operands": "ax, 0x42" }] -6683F0FF;[{ "Mnemonic": "xor", "Operands": "ax, 0xFFFF" }] +6683F042;[{ "Type": "Xor", "Operands": ["ax", "0x42"] }] +6683F0FF;[{ "Type": "Xor", "Operands": ["ax", "0xFFFF"] }] # 8-bit XOR tests # XOR r/m8, r8 (opcode 0x30) -30D8;[{ "Mnemonic": "xor", "Operands": "al, bl" }] -30C9;[{ "Mnemonic": "xor", "Operands": "cl, cl" }] +30D8;[{ "Type": "Xor", "Operands": ["al", "bl"] }] +30C9;[{ "Type": "Xor", "Operands": ["cl", "cl"] }] # XOR r8, r/m8 (opcode 0x32) -32D8;[{ "Mnemonic": "xor", "Operands": "bl, al" }] -32C9;[{ "Mnemonic": "xor", "Operands": "cl, cl" }] +32D8;[{ "Type": "Xor", "Operands": ["bl", "al"] }] +32C9;[{ "Type": "Xor", "Operands": ["cl", "cl"] }] # XOR r/m8, imm8 (opcode 0x80 /6) -80F042;[{ "Mnemonic": "xor", "Operands": "al, 0x42" }] -80F0FF;[{ "Mnemonic": "xor", "Operands": "al, 0xFF" }] +80F042;[{ "Type": "Xor", "Operands": ["al", "0x42"] }] +80F0FF;[{ "Type": "Xor", "Operands": ["al", "0xFF"] }] # Self-XOR tests (zeroing registers) -31C0;[{ "Mnemonic": "xor", "Operands": "eax, eax" }] -31DB;[{ "Mnemonic": "xor", "Operands": "ebx, ebx" }] -31C9;[{ "Mnemonic": "xor", "Operands": "ecx, ecx" }] -31D2;[{ "Mnemonic": "xor", "Operands": "edx, edx" }] +31C0;[{ "Type": "Xor", "Operands": ["eax", "eax"] }] +31DB;[{ "Type": "Xor", "Operands": ["ebx", "ebx"] }] +31C9;[{ "Type": "Xor", "Operands": ["ecx", "ecx"] }] +31D2;[{ "Type": "Xor", "Operands": ["edx", "edx"] }] # XOR with different addressing modes # XOR [ebp+0x8], eax (opcode 0x31) -314508;[{ "Mnemonic": "xor", "Operands": "dword ptr [ebp+0x08], eax" }] +314508;[{ "Type": "Xor", "Operands": ["dword ptr [ebp+0x08]", "eax"] }] # XOR eax, [ebp+0x8] (opcode 0x33) -334508;[{ "Mnemonic": "xor", "Operands": "eax, dword ptr [ebp+0x08]" }] +334508;[{ "Type": "Xor", "Operands": ["eax", "dword ptr [ebp+0x08]"] }] # XOR with other segment overrides # XOR ss:[ebx+0x10], ecx (opcode 0x31 with SS override) -36314B10;[{ "Mnemonic": "xor", "Operands": "dword ptr ss:[ebx+0x10], ecx" }] +36314B10;[{ "Type": "Xor", "Operands": ["dword ptr ss:[ebx+0x10]", "ecx"] }] # XOR ecx, ds:[ebx+0x10] (opcode 0x33 with DS override) -3E334B10;[{ "Mnemonic": "xor", "Operands": "ecx, dword ptr ds:[ebx+0x10]" }] +3E334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr ds:[ebx+0x10]"] }] # XOR ecx, es:[ebx+0x10] (opcode 0x33 with ES override) -26334B10;[{ "Mnemonic": "xor", "Operands": "ecx, dword ptr es:[ebx+0x10]" }] +26334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr es:[ebx+0x10]"] }] # XOR ecx, cs:[ebx+0x10] (opcode 0x33 with CS override) -2E334B10;[{ "Mnemonic": "xor", "Operands": "ecx, dword ptr cs:[ebx+0x10]" }] +2E334B10;[{ "Type": "Xor", "Operands": ["ecx", "dword ptr cs:[ebx+0x10]"] }] diff --git a/X86DisassemblerTests/TestDataProvider.cs b/X86DisassemblerTests/TestDataProvider.cs new file mode 100644 index 0000000..08fa8e8 --- /dev/null +++ b/X86DisassemblerTests/TestDataProvider.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Globalization; +using System.Reflection; +using CsvHelper; +using CsvHelper.Configuration; + +namespace X86DisassemblerTests; + +/// +/// Provides test data from CSV files in the TestData directory +/// +public class TestDataProvider : IEnumerable +{ + /// + /// Gets all CSV test files from the TestData directory + /// + /// An enumerable of test file names + private IEnumerable GetTestFiles() + { + // Get all CSV files from the TestData directory in the assembly + var assembly = Assembly.GetExecutingAssembly(); + var resourceNames = assembly.GetManifestResourceNames() + .Where(name => name.StartsWith("X86DisassemblerTests.TestData.") && name.EndsWith(".csv")); + + // Return all CSV files from the TestData directory + // All files have been converted to the new format + foreach (var resourceName in resourceNames) + { + // Return the full resource name + yield return resourceName; + } + } + + /// + /// Loads test entries from a CSV file + /// + /// The full resource name of the CSV file + /// An enumerable of TestFromFileEntry objects + private IEnumerable LoadTestEntries(string resourceName) + { + // Load the CSV test file from embedded resources + using var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream(resourceName); + + if (stream == null) + { + throw new InvalidOperationException($"Could not find {resourceName} embedded resource"); + } + + // Configure CSV reader with semicolon delimiter + var config = new CsvConfiguration(CultureInfo.InvariantCulture) + { + HasHeaderRecord = true, + Delimiter = ";", + BadDataFound = null, // Ignore bad data + AllowComments = true, // Enable comments in CSV files + Comment = '#', // Use # as the comment character + IgnoreBlankLines = true // Skip empty lines + }; + + using var streamReader = new StreamReader(stream); + using var csvReader = new CsvReader(streamReader, config); + + // Register class map for TestFromFileEntry + csvReader.Context.RegisterClassMap(); + + // Read all records from CSV + var entries = csvReader.GetRecords().ToList(); + + // Return each entry with its file name + foreach (var entry in entries) + { + yield return entry; + } + } + + /// + /// Returns an enumerator that provides test data for each test entry + /// + public IEnumerator GetEnumerator() + { + foreach (var resourceName in GetTestFiles()) + { + // Extract just the filename part for display purposes + string fileName = resourceName.Replace("X86DisassemblerTests.TestData.", ""); + int testIndex = 0; + + foreach (var entry in LoadTestEntries(resourceName)) + { + // Yield each test entry as a separate test case + // Include the file name and index for better test identification + yield return [fileName, testIndex++, entry]; + } + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/X86DisassemblerTests/TestFromFileEntry.cs b/X86DisassemblerTests/TestFromFileEntry.cs index be2601d..e6e4b31 100644 --- a/X86DisassemblerTests/TestFromFileEntry.cs +++ b/X86DisassemblerTests/TestFromFileEntry.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using CsvHelper.Configuration; using X86Disassembler.X86; using X86Disassembler.X86.Operands; @@ -18,60 +19,30 @@ public class TestFromFileEntry RawBytes = rawBytes; Instructions = instructions; } + + public override string ToString() + { + return $"{RawBytes}. {string.Join(";", Instructions)}"; + } } public class TestFromFileInstruction { // Keep the old properties for CSV deserialization - public string Mnemonic { get; set; } = string.Empty; - public string Operands { get; set; } = string.Empty; - - // Add new properties for comparison with actual Instruction objects - public InstructionType Type => ConvertMnemonicToType(Mnemonic); - + public string[] Operands { get; set; } = []; + + // Mnemonic + [JsonConverter(typeof(JsonStringEnumConverter))] + public InstructionType Type { get; set; } + // Parameterless constructor required by CsvHelper public TestFromFileInstruction() { } - public TestFromFileInstruction(string mnemonic, string operands) + public override string ToString() { - Mnemonic = mnemonic; - Operands = operands; - } - - // Helper method to convert mnemonic string to InstructionType - private InstructionType ConvertMnemonicToType(string mnemonic) - { - // Convert mnemonic to InstructionType - return mnemonic.ToLowerInvariant() switch - { - "add" => InstructionType.Add, - "adc" => InstructionType.Adc, - "and" => InstructionType.And, - "call" => InstructionType.Call, - "cmp" => InstructionType.Cmp, - "dec" => InstructionType.Dec, - "inc" => InstructionType.Inc, - "int3" => InstructionType.Int, - "jmp" => InstructionType.Jmp, - "jz" => InstructionType.Jz, - "jnz" => InstructionType.Jnz, - "jge" => InstructionType.Jge, - "lea" => InstructionType.Lea, - "mov" => InstructionType.Mov, - "nop" => InstructionType.Nop, - "or" => InstructionType.Or, - "pop" => InstructionType.Pop, - "push" => InstructionType.Push, - "ret" => InstructionType.Ret, - "sbb" => InstructionType.Sbb, - "sub" => InstructionType.Sub, - "test" => InstructionType.Test, - "xchg" => InstructionType.Xchg, - "xor" => InstructionType.Xor, - _ => InstructionType.Unknown - }; + return $"{Type} {string.Join(",", Operands)}"; } } diff --git a/X86DisassemblerTests/X86DisassemblerTests.csproj b/X86DisassemblerTests/X86DisassemblerTests.csproj index 35ee786..44e2e97 100644 --- a/X86DisassemblerTests/X86DisassemblerTests.csproj +++ b/X86DisassemblerTests/X86DisassemblerTests.csproj @@ -1,41 +1,77 @@ - - net8.0 - enable - enable + + net8.0 + enable + enable - false - true - + false + true + - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +