diff --git a/ParkanPlayground.sln.DotSettings.user b/ParkanPlayground.sln.DotSettings.user index c5cd8ae..9c4328e 100644 --- a/ParkanPlayground.sln.DotSettings.user +++ b/ParkanPlayground.sln.DotSettings.user @@ -1,7 +1,10 @@  ForceIncluded ForceIncluded + ForceIncluded + ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -20,5 +23,7 @@ <SessionState ContinuousTestingMode="0" IsActive="True" Name="RunTestsOnJson" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> <TestId>xUnit::D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5::net8.0::X86DisassemblerTests.GeneralDisassemblerInstructionTests.RunTestsOnJson</TestId> + <TestId>xUnit::D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5::net8.0::X86DisassemblerTests.PushRegTests.PushRegTests</TestId> + <TestId>xUnit::D6A1F5A9-0C7A-4F8F-B8C5-83E9D3F3A1D5::net8.0::X86DisassemblerTests.RawFromFileDisassemblyTests</TestId> </TestAncestor> </SessionState> \ No newline at end of file diff --git a/X86DisassemblerTests/CsvJsonConverter.cs b/X86DisassemblerTests/CsvJsonConverter.cs new file mode 100644 index 0000000..0db826a --- /dev/null +++ b/X86DisassemblerTests/CsvJsonConverter.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using CsvHelper; +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; + +namespace X86DisassemblerTests; + +// ReSharper disable once ClassNeverInstantiated.Global +public sealed class CsvJsonConverter : DefaultTypeConverter +{ + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text is null) + { + return null; + } + + return JsonSerializer.Deserialize(text); + } + + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + return JsonSerializer.Serialize(value); + } +} \ No newline at end of file diff --git a/X86DisassemblerTests/GeneralDisassemblerInstructionTests.cs b/X86DisassemblerTests/GeneralDisassemblerInstructionTests.cs deleted file mode 100644 index 28ca317..0000000 --- a/X86DisassemblerTests/GeneralDisassemblerInstructionTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Reflection; -using System.Text.Json; -using Xunit; -using X86Disassembler.X86; - -namespace X86DisassemblerTests; - -/// -/// General tests for the X86 disassembler using a JSON test file -/// -public class GeneralDisassemblerInstructionTests -{ - /// - /// Runs tests on all instructions defined in the JSON file - /// - [Fact] - public void RunTestsOnJson() - { - // Load the JSON test file from embedded resources - using var jsonStream = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("X86DisassemblerTests.instruction_test.json"); - - if (jsonStream == null) - { - throw new InvalidOperationException("Could not find instruction_test.json embedded resource"); - } - - // Deserialize the JSON file - var instructions = JsonSerializer.Deserialize>(jsonStream)!; - - // Run tests for each instruction - for (var index = 0; index < instructions.Count; index++) - { - var test = instructions[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.Disassembled.Count != disassembledInstructions.Count) - { - Assert.Fail( - $"Failed verifying test {index}: {test.RawBytes}. Instruction count mismatch.\n" + - $"Expected \"{test.Disassembled.Count}\", but got \"{disassembledInstructions.Count}\".\n" + - $"Disassembled instructions:\n" + - $"{string.Join("\n", disassembledInstructions)}" - ); - } - - // Verify each instruction - for (int i = 0; i < test.Disassembled.Count; i++) - { - var expected = test.Disassembled[i]; - var actual = disassembledInstructions[i]; - - if (expected.Mnemonic != actual.Mnemonic) - { - Assert.Fail( - $"Failed verifying test {index}: {test.RawBytes}. Instruction {i}. Mnemonic mismatch. " + - $"Expected \"{expected.Mnemonic}\", but got {actual.Mnemonic}\"" - ); - } - if (expected.Operands != actual.Operands) - { - Assert.Fail( - $"Failed verifying test {index}: {test.RawBytes}. Instruction {i}. Operands mismatch. " + - $"Expected \"{expected.Operands}\", but got \"{actual.Operands}\"" - ); - } - } - } - } - - /// - /// Converts a hex string to a byte array - /// - /// The hex string to convert - /// The byte array - private static byte[] HexStringToByteArray(string hex) - { - // Remove any non-hex characters - hex = hex.Replace(" ", "") - .Replace("-", ""); - - // Create a byte array - byte[] bytes = new byte[hex.Length / 2]; - - // Convert each pair of hex characters to a byte - for (int i = 0; i < hex.Length; i += 2) - { - bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); - } - - return bytes; - } -} \ No newline at end of file diff --git a/X86DisassemblerTests/InstructionTests/SubInstructionTests.cs b/X86DisassemblerTests/InstructionTests/SubInstructionTests.cs index c9fab47..cdc131c 100644 --- a/X86DisassemblerTests/InstructionTests/SubInstructionTests.cs +++ b/X86DisassemblerTests/InstructionTests/SubInstructionTests.cs @@ -69,13 +69,13 @@ public class SubInstructionTests } /// - /// Tests the SubImmFromRm32SignExtendedHandler for decoding SUB r/m32, negative imm8 instruction (sign-extended) + /// Tests the SubImmFromRm32SignExtendedHandler for decoding SUB r/m32, imm8 instruction with negative value /// [Fact] public void SubImmFromRm32SignExtendedHandler_DecodesSubRm32NegativeImm8_Correctly() { // Arrange - // SUB EAX, 0xF0 (83 E8 F0) - Subtract sign-extended 0xF0 from EAX + // SUB EAX, -0x10 (83 E8 F0) - Subtract sign-extended -0x10 from EAX byte[] codeBuffer = new byte[] { 0x83, 0xE8, 0xF0 }; var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); @@ -111,23 +111,25 @@ public class SubInstructionTests } /// - /// Tests the SubR32Rm32Handler for decoding SUB r32, r/m32 instruction + /// Tests a sequence of SUB instructions in a common pattern /// [Fact] - public void SubR32Rm32Handler_DecodesSubR32Rm32_Correctly() + public void SubInstruction_DecodesSubSequence_Correctly() { // Arrange - // SUB EBX, EAX (2B D8) - Subtract EAX from EBX - byte[] codeBuffer = new byte[] { 0x2B, 0xD8 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + // SUB ESP, 0x10 (83 EC 10) - Create stack space + byte[] codeBuffer = new byte[] { 0x83, 0xEC, 0x10 }; + var disassembler = new Disassembler(codeBuffer, 0); // Act - var instruction = decoder.DecodeInstruction(); + var instructions = disassembler.Disassemble(); // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("ebx, eax", instruction.Operands); + Assert.Single(instructions); + + // Instruction: SUB ESP, 0x10 + Assert.Equal("sub", instructions[0].Mnemonic); + Assert.Equal("esp, 0x10", instructions[0].Operands); } /// @@ -170,6 +172,26 @@ public class SubInstructionTests Assert.Equal("dword ptr [ebx+0x10], ecx", instruction.Operands); } + /// + /// Tests the SubR32Rm32Handler for decoding SUB r32, r/m32 instruction + /// + [Fact] + public void SubR32Rm32Handler_DecodesSubR32Rm32_Correctly() + { + // Arrange + // SUB EBX, EAX (2B D8) - Subtract EAX from EBX + byte[] codeBuffer = new byte[] { 0x2B, 0xD8 }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("sub", instruction.Mnemonic); + Assert.Equal("ebx, eax", instruction.Operands); + } + /// /// Tests the SubR32Rm32Handler for decoding SUB r32, memory instruction /// diff --git a/X86DisassemblerTests/JsonInstructionEntry.cs b/X86DisassemblerTests/JsonInstructionEntry.cs deleted file mode 100644 index e741385..0000000 --- a/X86DisassemblerTests/JsonInstructionEntry.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace X86DisassemblerTests; - -public class JsonInstructionEntry -{ - public string RawBytes { get; set; } = ""; - public List Disassembled { get; set; } = []; -} - -public class JsonDisassembledInstruction -{ - public string Mnemonic { get; set; } = ""; - public string Operands { get; set; } = ""; -} \ No newline at end of file diff --git a/X86DisassemblerTests/RawFromFileDisassemblyTests.cs b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs new file mode 100644 index 0000000..f25a133 --- /dev/null +++ b/X86DisassemblerTests/RawFromFileDisassemblyTests.cs @@ -0,0 +1,141 @@ +using System.Globalization; +using System.Reflection; +using CsvHelper; +using CsvHelper.Configuration; +using X86Disassembler.X86; +using Xunit.Abstractions; + +namespace X86DisassemblerTests; + +public class RawFromFileDisassemblyTests(ITestOutputHelper output) +{ + [Theory] + [InlineData("pushreg_tests.csv")] + [InlineData("popreg_tests.csv")] + public void RunTests(string file) + { + // Load the CSV test file from embedded resources + using var stream = Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"X86DisassemblerTests.TestData.{file}"); + + if (stream == null) + { + throw new InvalidOperationException($"Could not find {file} embedded resource"); + } + + // Configure CSV reader with semicolon delimiter + var config = new CsvConfiguration(CultureInfo.InvariantCulture) + { + HasHeaderRecord = true, + Delimiter = ";", + BadDataFound = null // Ignore bad data + }; + + 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) + { + AssertFailWithReason( + index, + file, + test, + disassembledInstructions, + "Instruction count mismatch" + ); + } + + // Verify each instruction + for (int i = 0; i < test.Instructions.Count; i++) + { + var expected = test.Instructions[i]; + var actual = disassembledInstructions[i]; + + if (expected.Mnemonic != actual.Mnemonic) + { + AssertFailWithReason( + index, + file, + test, + disassembledInstructions, + "Mnemonic mismatch" + ); + } + + if (expected.Operands != actual.Operands) + { + AssertFailWithReason( + index, + file, + test, + disassembledInstructions, + "Operands mismatch" + ); + } + } + + output.WriteLine( + $"Test succeeded {index} of file {file}: {test.RawBytes}.\n" + + $"Instruction count \"{test.Instructions.Count}\".\n" + + $"{string.Join("\n", test.Instructions.Select(x => $"{x.Mnemonic} {x.Operands}"))}\n" + ); + } + } + + private static void AssertFailWithReason(int index, string file, TestFromFileEntry test, List disassembledInstructions, string reason) + { + Assert.Fail( + $"Failed verifying test {index} of file {file}: {test.RawBytes}. {reason}.\n" + + $"Expected \"{test.Instructions.Count}\", but got \"{disassembledInstructions.Count}\".\n" + + $"\n" + + $"Expected instructions:\n" + + $"{string.Join("\n", test.Instructions.Select(x => $"{x.Mnemonic} {x.Operands}"))}\n" + + $"\n" + + $"Disassembled instructions:\n" + + $"{string.Join("\n", disassembledInstructions)}" + ); + } + + /// + /// Converts a hex string to a byte array + /// + /// The hex string to convert + /// The byte array + private static byte[] HexStringToByteArray(string hex) + { + // Remove any non-hex characters + + // Create a byte array + byte[] bytes = new byte[hex.Length / 2]; + + // Convert each pair of hex characters to a byte + for (int i = 0; i < hex.Length; i += 2) + { + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + } + + return bytes; + } +} \ No newline at end of file diff --git a/X86DisassemblerTests/SubInstructionTests.cs b/X86DisassemblerTests/SubInstructionTests.cs deleted file mode 100644 index 506313e..0000000 --- a/X86DisassemblerTests/SubInstructionTests.cs +++ /dev/null @@ -1,249 +0,0 @@ -namespace X86DisassemblerTests; - -using System; -using Xunit; -using X86Disassembler.X86; -using X86Disassembler.X86.Handlers.Sub; - -/// -/// Tests for SUB instruction handlers -/// -public class SubInstructionTests -{ - /// - /// Tests the SubImmFromRm32Handler for decoding SUB r/m32, imm32 instruction - /// - [Fact] - public void SubImmFromRm32Handler_DecodesSubRm32Imm32_Correctly() - { - // Arrange - // SUB EAX, 0x12345678 (81 E8 78 56 34 12) - Subtract 0x12345678 from EAX - byte[] codeBuffer = new byte[] { 0x81, 0xE8, 0x78, 0x56, 0x34, 0x12 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("eax, 0x12345678", instruction.Operands); - } - - /// - /// Tests the SubImmFromRm32Handler for decoding SUB memory, imm32 instruction - /// - [Fact] - public void SubImmFromRm32Handler_DecodesSubMemImm32_Correctly() - { - // Arrange - // SUB [EBX+0x10], 0x12345678 (81 6B 10 78 56 34 12) - Subtract 0x12345678 from memory at [EBX+0x10] - byte[] codeBuffer = new byte[] { 0x81, 0x6B, 0x10, 0x78, 0x56, 0x34, 0x12 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - // The actual output from the disassembler for this instruction - Assert.Equal("dword ptr [ebx+0x10], 0x12345678", instruction.Operands); - } - - /// - /// Tests the SubImmFromRm32SignExtendedHandler for decoding SUB r/m32, imm8 instruction (sign-extended) - /// - [Fact] - public void SubImmFromRm32SignExtendedHandler_DecodesSubRm32Imm8_Correctly() - { - // Arrange - // SUB EAX, 0x42 (83 E8 42) - Subtract sign-extended 0x42 from EAX - byte[] codeBuffer = new byte[] { 0x83, 0xE8, 0x42 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("eax, 0x42", instruction.Operands); - } - - /// - /// Tests the SubImmFromRm32SignExtendedHandler for decoding SUB r/m32, imm8 instruction with negative value - /// - [Fact] - public void SubImmFromRm32SignExtendedHandler_DecodesSubRm32NegativeImm8_Correctly() - { - // Arrange - // SUB EAX, -0x10 (83 E8 F0) - Subtract sign-extended -0x10 from EAX - byte[] codeBuffer = new byte[] { 0x83, 0xE8, 0xF0 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - // F0 is -16 in two's complement, should be sign-extended to 0xFFFFFFF0 - Assert.Equal("eax, 0xFFFFFFF0", instruction.Operands); - } - - /// - /// Tests the SubImmFromRm32SignExtendedHandler for decoding SUB memory, imm8 instruction - /// - [Fact] - public void SubImmFromRm32SignExtendedHandler_DecodesSubMemImm8_Correctly() - { - // Arrange - // SUB [EBX+0x10], 0x42 (83 6B 10 42) - Subtract sign-extended 0x42 from memory at [EBX+0x10] - byte[] codeBuffer = new byte[] { 0x83, 0x6B, 0x10, 0x42 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - // The actual output from the disassembler for this instruction - Assert.Equal("dword ptr [ebx+0x10], 0x42", instruction.Operands); - } - - /// - /// Tests a sequence of SUB instructions in a common pattern - /// - [Fact] - public void SubInstruction_DecodesSubSequence_Correctly() - { - // Arrange - // SUB ESP, 0x10 (83 EC 10) - Create stack space - byte[] codeBuffer = new byte[] { 0x83, 0xEC, 0x10 }; - var disassembler = new Disassembler(codeBuffer, 0); - - // Act - var instructions = disassembler.Disassemble(); - - // Assert - Assert.Single(instructions); - - // Instruction: SUB ESP, 0x10 - Assert.Equal("sub", instructions[0].Mnemonic); - Assert.Equal("esp, 0x10", instructions[0].Operands); - } - - /// - /// Tests the SubRm32R32Handler for decoding SUB r/m32, r32 instruction - /// - [Fact] - public void SubRm32R32Handler_DecodesSubRm32R32_Correctly() - { - // Arrange - // SUB EAX, EBX (29 D8) - Subtract EBX from EAX - byte[] codeBuffer = new byte[] { 0x29, 0xD8 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("eax, ebx", instruction.Operands); - } - - /// - /// Tests the SubRm32R32Handler for decoding SUB memory, r32 instruction - /// - [Fact] - public void SubRm32R32Handler_DecodesSubMemR32_Correctly() - { - // Arrange - // SUB [EBX+0x10], ECX (29 4B 10) - Subtract ECX from memory at [EBX+0x10] - byte[] codeBuffer = new byte[] { 0x29, 0x4B, 0x10 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("dword ptr [ebx+0x10], ecx", instruction.Operands); - } - - /// - /// Tests the SubR32Rm32Handler for decoding SUB r32, r/m32 instruction - /// - [Fact] - public void SubR32Rm32Handler_DecodesSubR32Rm32_Correctly() - { - // Arrange - // SUB EBX, EAX (2B D8) - Subtract EAX from EBX - byte[] codeBuffer = new byte[] { 0x2B, 0xD8 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("ebx, eax", instruction.Operands); - } - - /// - /// Tests the SubR32Rm32Handler for decoding SUB r32, memory instruction - /// - [Fact] - public void SubR32Rm32Handler_DecodesSubR32Mem_Correctly() - { - // Arrange - // SUB ECX, [EBX+0x10] (2B 4B 10) - Subtract memory at [EBX+0x10] from ECX - byte[] codeBuffer = new byte[] { 0x2B, 0x4B, 0x10 }; - var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - - // Act - var instruction = decoder.DecodeInstruction(); - - // Assert - Assert.NotNull(instruction); - Assert.Equal("sub", instruction.Mnemonic); - Assert.Equal("ecx, dword ptr [ebx+0x10]", instruction.Operands); - } - - /// - /// Tests a sequence of SUB instructions with different encoding - /// - [Fact] - public void SubInstruction_DecodesComplexSubSequence_Correctly() - { - // Arrange - // SUB ESP, 0x10 (83 EC 10) - Create stack space - // SUB EAX, EBX (29 D8) - Subtract EBX from EAX - // SUB ECX, [EBP-4] (2B 4D FC) - Subtract memory at [EBP-4] from ECX - byte[] codeBuffer = new byte[] { 0x83, 0xEC, 0x10, 0x29, 0xD8, 0x2B, 0x4D, 0xFC }; - var disassembler = new Disassembler(codeBuffer, 0); - - // Act - var instructions = disassembler.Disassemble(); - - // Assert - Assert.Equal(3, instructions.Count); - - // First instruction: SUB ESP, 0x10 - Assert.Equal("sub", instructions[0].Mnemonic); - Assert.Equal("esp, 0x10", instructions[0].Operands); - - // Second instruction: SUB EAX, EBX - Assert.Equal("sub", instructions[1].Mnemonic); - Assert.Equal("eax, ebx", instructions[1].Operands); - - // Third instruction: SUB ECX, [EBP-4] - Assert.Equal("sub", instructions[2].Mnemonic); - Assert.Equal("ecx, dword ptr [ebp-0x04]", instructions[2].Operands); - } -} diff --git a/X86DisassemblerTests/TestData/popreg_tests.csv b/X86DisassemblerTests/TestData/popreg_tests.csv new file mode 100644 index 0000000..c0ee69c --- /dev/null +++ b/X86DisassemblerTests/TestData/popreg_tests.csv @@ -0,0 +1,9 @@ +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 diff --git a/X86DisassemblerTests/TestData/pushreg_tests.csv b/X86DisassemblerTests/TestData/pushreg_tests.csv new file mode 100644 index 0000000..c8261d9 --- /dev/null +++ b/X86DisassemblerTests/TestData/pushreg_tests.csv @@ -0,0 +1,9 @@ +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 diff --git a/X86DisassemblerTests/TestFromFileEntry.cs b/X86DisassemblerTests/TestFromFileEntry.cs new file mode 100644 index 0000000..d4f7e7d --- /dev/null +++ b/X86DisassemblerTests/TestFromFileEntry.cs @@ -0,0 +1,48 @@ +using CsvHelper.Configuration; + +namespace X86DisassemblerTests; + +public class TestFromFileEntry +{ + public string RawBytes { get; set; } = string.Empty; + public List Instructions { get; set; } = new(); + + public TestFromFileEntry() + { + } + + public TestFromFileEntry(string rawBytes, List instructions) + { + RawBytes = rawBytes; + Instructions = instructions; + } +} + +public class TestFromFileInstruction +{ + public string Mnemonic { get; set; } = string.Empty; + public string Operands { get; set; } = string.Empty; + + // Parameterless constructor required by CsvHelper + public TestFromFileInstruction() + { + } + + public TestFromFileInstruction(string mnemonic, string operands) + { + Mnemonic = mnemonic; + Operands = operands; + } +} + +public sealed class TestFromFileEntryMap : ClassMap +{ + public TestFromFileEntryMap() + { + Map(m => m.RawBytes) + .Name("RawBytes"); + Map(m => m.Instructions) + .Name("Instructions") + .TypeConverter>>(); + } +} \ No newline at end of file diff --git a/X86DisassemblerTests/X86DisassemblerTests.csproj b/X86DisassemblerTests/X86DisassemblerTests.csproj index 3042d62..fc805f6 100644 --- a/X86DisassemblerTests/X86DisassemblerTests.csproj +++ b/X86DisassemblerTests/X86DisassemblerTests.csproj @@ -10,6 +10,7 @@ + @@ -27,8 +28,11 @@ + + + diff --git a/X86DisassemblerTests/instruction_test.json b/X86DisassemblerTests/instruction_test.json index 2579c73..d054e3f 100644 --- a/X86DisassemblerTests/instruction_test.json +++ b/X86DisassemblerTests/instruction_test.json @@ -1,148 +1,4 @@ [ - { - "RawBytes": "50", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "eax" - } - ] - }, - { - "RawBytes": "51", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "ecx" - } - ] - }, - { - "RawBytes": "52", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "edx" - } - ] - }, - { - "RawBytes": "53", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "ebx" - } - ] - }, - { - "RawBytes": "54", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "esp" - } - ] - }, - { - "RawBytes": "55", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "ebp" - } - ] - }, - { - "RawBytes": "56", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "esi" - } - ] - }, - { - "RawBytes": "57", - "Disassembled": [ - { - "Mnemonic": "push", - "Operands": "edi" - } - ] - }, - { - "RawBytes": "58", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "eax" - } - ] - }, - { - "RawBytes": "59", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "ecx" - } - ] - }, - { - "RawBytes": "5A", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "edx" - } - ] - }, - { - "RawBytes": "5B", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "ebx" - } - ] - }, - { - "RawBytes": "5C", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "esp" - } - ] - }, - { - "RawBytes": "5D", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "ebp" - } - ] - }, - { - "RawBytes": "5E", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "esi" - } - ] - }, - { - "RawBytes": "5F", - "Disassembled": [ - { - "Mnemonic": "pop", - "Operands": "edi" - } - ] - }, { "RawBytes": "6810000000", "Disassembled": [