diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index a02339a4..d7ffd709 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -181,8 +181,8 @@ boost::optional&> DecodeArm(u32 instruction) { //INST(&V::arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnddddvvvvvrr0mmmm"), //INST(&V::arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnddddvvvvvvvvvvvv"), //INST(&V::arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnddddvvvvvrr0mmmm"), - //INST(&V::arm_LDRBT, "LDRBT (A1)", "----0100-111--------------------"), - //INST(&V::arm_LDRBT, "LDRBT (A2)", "----0110-111---------------0----"), + //INST(&V::arm_LDRBT, "LDRBT (A1)", "cccc0100u111nnnnttttvvvvvvvvvvvv"), + //INST(&V::arm_LDRBT, "LDRBT (A2)", "cccc0110u111nnnnttttvvvvvrr0mmmm"), //INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnddddvvvv1101vvvv"), // v5E //INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnndddd00001101mmmm"), // v5E //INST(&V::arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnddddvvvv1011vvvv"), @@ -197,22 +197,22 @@ boost::optional&> DecodeArm(u32 instruction) { //INST(&V::arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnndddd00001111mmmm"), //INST(&V::arm_LDRSHT, "LDRSHT (A1)", "----0000-111------------1111----"), //INST(&V::arm_LDRSHT, "LDRSHT (A2)", "----0000-011--------00001111----"), - //INST(&V::arm_LDRT, "LDRT (A1)", "----0100-011--------------------"), - //INST(&V::arm_LDRT, "LDRT (A2)", "----0110-011---------------0----"), + //INST(&V::arm_LDRT, "LDRT (A1)", "cccc0100u011nnnnttttvvvvvvvvvvvv"), + //INST(&V::arm_LDRT, "LDRT (A2)", "cccc0110u011nnnnttttvvvvvrr0mmmm"), //INST(&V::arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnddddvvvvvvvvvvvv"), //INST(&V::arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnddddvvvvvrr0mmmm"), //INST(&V::arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnddddvvvvvvvvvvvv"), //INST(&V::arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnddddvvvvvrr0mmmm"), - //INST(&V::arm_STRBT, "STRBT (A1)", "----0100-110--------------------"), - //INST(&V::arm_STRBT, "STRBT (A2)", "----0110-110---------------0----"), + //INST(&V::arm_STRBT, "STRBT (A1)", "cccc0100u110nnnnttttvvvvvvvvvvvv"), + //INST(&V::arm_STRBT, "STRBT (A2)", "cccc0110u110nnnnttttvvvvvrr0mmmm"), //INST(&V::arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnddddvvvv1111vvvv"), // v5E //INST(&V::arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnndddd00001111mmmm"), // v5E //INST(&V::arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnddddvvvv1011vvvv"), //INST(&V::arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnndddd00001011mmmm"), //INST(&V::arm_STRHT, "STRHT (A1)", "----0000-110------------1011----"), //INST(&V::arm_STRHT, "STRHT (A2)", "----0000-010--------00001011----"), - //INST(&V::arm_STRT, "STRT (A1)", "----0100-010--------------------"), - //INST(&V::arm_STRT, "STRT (A2)", "----0110-010---------------0----"), + //INST(&V::arm_STRT, "STRT (A1)", "cccc0100u010nnnnttttvvvvvvvvvvvv"), + //INST(&V::arm_STRT, "STRT (A2)", "cccc0110u010nnnnttttvvvvvrr0mmmm"), // Load/Store Multiple instructions //INST(&V::arm_LDM, "LDM", "cccc100pu0w1nnnnxxxxxxxxxxxxxxxx"), // all diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index d2834eb6..a520448f 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -366,29 +366,199 @@ TEST_CASE("Fuzz ARM reversal instructions", "[JitX64]") { return Dynarmic::Common::Bits<0, 3>(instr) != 0b1111 && Dynarmic::Common::Bits<12, 15>(instr) != 0b1111; }; - const std::array reg_instructions = { + const std::array rev_instructions = { { - InstructionGenerator("cccc011010111111dddd11110011mmmm", is_valid), - InstructionGenerator("cccc011010111111dddd11111011mmmm", is_valid), - InstructionGenerator("cccc011011111111dddd11111011mmmm", is_valid), + InstructionGenerator("0000011010111111dddd11110011mmmm", is_valid), + InstructionGenerator("0000011010111111dddd11111011mmmm", is_valid), + InstructionGenerator("0000011011111111dddd11111011mmmm", is_valid), } }; SECTION("REV tests") { - FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { - return reg_instructions[0].Generate(); + FuzzJitArm(1, 1, 10000, [&rev_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return rev_instructions[0].Generate() | (cond << 28); }); } SECTION("REV16 tests") { - FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { - return reg_instructions[1].Generate(); + FuzzJitArm(1, 1, 10000, [&rev_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return rev_instructions[1].Generate() | (cond << 28); }); } SECTION("REVSH tests") { - FuzzJitArm(1, 1, 10000, [®_instructions]() -> u32 { - return reg_instructions[2].Generate(); + FuzzJitArm(1, 1, 10000, [&rev_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return rev_instructions[2].Generate() | (cond << 28); }); } } + +TEST_CASE("Fuzz ARM Load/Store instructions", "[JitX64]") { + auto forbid_r15 = [](u32 inst) -> bool { + return Dynarmic::Common::Bits<12, 15>(inst) != 0b1111; + }; + + auto forbid_r14_and_r15 = [](u32 inst) -> bool { + return Dynarmic::Common::Bits<13, 15>(inst) != 0b111; + }; + + const std::array doubleword_instructions = { + { + // Load + InstructionGenerator("0000000pu1w0nnnnddd0vvvv1101vvvv", forbid_r14_and_r15), + InstructionGenerator("0000000pu0w0nnnnddd000001101mmmm", forbid_r14_and_r15), + + // Store + InstructionGenerator("0000000pu1w0nnnnddd0vvvv1111vvvv", forbid_r14_and_r15), + InstructionGenerator("0000000pu0w0nnnnddd000001111mmmm", forbid_r14_and_r15), + } + }; + + const std::array word_instructions = { + { + // Load + InstructionGenerator("0000010pu0w1nnnnddddvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("0000011pu0w1nnnnddddvvvvvrr0mmmm", forbid_r15), + InstructionGenerator("00000100u011nnnnttttmmmmmmmmmmmm", forbid_r15), + InstructionGenerator("00000110u011nnnnttttvvvvvrr0mmmm", forbid_r15), + + // Store + InstructionGenerator("0000010pu0w0nnnnddddvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("0000011pu0w0nnnnddddvvvvvrr0mmmm", forbid_r15), + InstructionGenerator("00000100u010nnnnttttvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("00000110u010nnnnttttvvvvvrr0mmmm", forbid_r15), + } + }; + + const std::array halfword_instructions = { + { + // Load + InstructionGenerator("0000000pu1w1nnnnddddvvvv1011vvvv", forbid_r15), + InstructionGenerator("0000000pu0w1nnnndddd00001011mmmm", forbid_r15), + // InstructionGenerator("----0000-111------------1011----"), // LDRHT (A1) Not available in ARMv6K + // InstructionGenerator("----0000-011--------00001011----"), // LDRHT (A2) Not available in ARMv6K + InstructionGenerator("0000000pu1w1nnnnddddvvvv1111vvvv", forbid_r15), + InstructionGenerator("0000000pu0w1nnnndddd00001111mmmm", forbid_r15), + // InstructionGenerator("----0000-111------------1111----"), // LDRSHT (A1) Not available in ARMv6K + // InstructionGenerator("----0000-011--------00001111----"), // LDRSHT (A2) Not available in ARMv6K + + + // Store + InstructionGenerator("0000000pu1w0nnnnddddvvvv1011vvvv", forbid_r15), + InstructionGenerator("0000000pu0w0nnnndddd00001011mmmm", forbid_r15), + // InstructionGenerator("----0000-110------------1011----"), // STRHT (A1) Not available in ARMv6K + // InstructionGenerator("----0000-010--------00001011----"), // STRHT (A2) Not available in ARMv6K + } + }; + + const std::array byte_instructions = { + { + // Load + InstructionGenerator("0000010pu1w1nnnnddddvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("0000011pu1w1nnnnddddvvvvvrr0mmmm", forbid_r15), + InstructionGenerator("00000100u111nnnnttttvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("00000110u111nnnnttttvvvvvrr0mmmm", forbid_r15), + InstructionGenerator("0000000pu1w1nnnnddddvvvv1101vvvv", forbid_r15), + InstructionGenerator("0000000pu0w1nnnndddd00001101mmmm", forbid_r15), + // InstructionGenerator("----0000-111------------1101----"), // LDRSBT (A1) Not available in ARMv6K + // InstructionGenerator("----0000-011--------00001101----"), // LDRSBT (A2) Not available in ARMv6K + + + // Store + InstructionGenerator("0000010pu1w0nnnnddddvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("0000011pu1w0nnnnddddvvvvvrr0mmmm", forbid_r15), + InstructionGenerator("00000100u110nnnnttttvvvvvvvvvvvv", forbid_r15), + InstructionGenerator("00000110u110nnnnttttvvvvvrr0mmmm", forbid_r15), + } + }; + + SECTION("Doubleword tests") { + FuzzJitArm(1, 1, 10000, [&doubleword_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + + return doubleword_instructions[RandInt(0, doubleword_instructions.size() - 1)].Generate() | (cond << 28); + }); + } + + SECTION("Word tests") { + FuzzJitArm(1, 1, 10000, [&word_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return word_instructions[RandInt(0, word_instructions.size() - 1)].Generate() | (cond << 28); + }); + } + + SECTION("Halfword tests") { + FuzzJitArm(1, 1, 10000, [&halfword_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return halfword_instructions[RandInt(0, halfword_instructions.size() - 1)].Generate() | (cond << 28); + }); + } + + SECTION("Byte tests") { + FuzzJitArm(1, 1, 10000, [&byte_instructions]() -> u32 { + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + return byte_instructions[RandInt(0, byte_instructions.size() - 1)].Generate() | (cond << 28); + }); + } + + SECTION("Mixed tests") { + FuzzJitArm(10, 10, 10000, [&]() -> u32 { + size_t selection = RandInt(0, 3); + + u32 cond = 0xE; + // Have a one-in-twenty-five chance of actually having a cond. + if (RandInt(1, 25) == 1) { + cond = RandInt(0x0, 0xD); + } + + switch (selection) { + case 0: + return doubleword_instructions[RandInt(0, doubleword_instructions.size() - 1)].Generate() | (cond << 28); + case 1: + return word_instructions[RandInt(0, word_instructions.size() - 1)].Generate() | (cond << 28); + case 2: + return halfword_instructions[RandInt(0, halfword_instructions.size() - 1)].Generate() | (cond << 28); + case 3: + return byte_instructions[RandInt(0, byte_instructions.size() - 1)].Generate() | (cond << 28); + } + + return 0; + }); + } + + SECTION("Write to PC") { + // TODO + FAIL(); + } +} \ No newline at end of file