From 9c4f2344171736f95f523af6b88c95a6f5d3bd2a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 15 Jul 2018 11:58:53 +0100 Subject: [PATCH] fuzz_with_unicorn: Avoid self-modifying code * Don't immediately terminate when unicorn raises an interrupt * Detect self-modifying code --- tests/A64/fuzz_with_unicorn.cpp | 19 ++++++++++++++++--- tests/A64/testenv.h | 1 + tests/A64/unicorn_emu/unicorn.cpp | 6 +++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/A64/fuzz_with_unicorn.cpp b/tests/A64/fuzz_with_unicorn.cpp index 40ad89e4..05b39739 100644 --- a/tests/A64/fuzz_with_unicorn.cpp +++ b/tests/A64/fuzz_with_unicorn.cpp @@ -119,7 +119,7 @@ static u32 GenFloatInst(u64 pc, bool is_last_inst) { // Approximation. Produces incorrect results. "FMADD_float", "FMSUB_float", "FNMADD_float", "FNMSUB_float", // Requires investigation (temporarily disabled). - "FDIV_2", + "FDIV_1", "FDIV_2", }; std::vector result; @@ -150,8 +150,8 @@ static u32 GenFloatInst(u64 pc, bool is_last_inst) { static void RunTestInstance(const Unicorn::RegisterArray& regs, const Unicorn::VectorArray& vecs, const size_t instructions_offset, const std::vector& instructions, const u32 pstate, const u32 fpcr) { - static TestEnv jit_env; - static TestEnv uni_env; + static TestEnv jit_env{}; + static TestEnv uni_env{}; std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + instructions_offset); std::copy(instructions.begin(), instructions.end(), uni_env.code_mem.begin() + instructions_offset); @@ -159,6 +159,8 @@ static void RunTestInstance(const Unicorn::RegisterArray& regs, const Unicorn::V uni_env.code_mem[instructions.size() + instructions_offset] = 0x14000000; // B . jit_env.modified_memory.clear(); uni_env.modified_memory.clear(); + jit_env.interrupts.clear(); + uni_env.interrupts.clear(); Dynarmic::A64::UserConfig jit_user_config{&jit_env}; // The below corresponds to the settings for qemu's aarch64_max_initfn @@ -238,14 +240,25 @@ static void RunTestInstance(const Unicorn::RegisterArray& regs, const Unicorn::V fmt::print("x86_64:\n"); fmt::print("{}\n", jit.Disassemble()); + + fmt::print("Interrupts:\n"); + for (auto& i : uni_env.interrupts) { + puts(i.c_str()); + } }; + REQUIRE(uni_env.code_mem_modified_by_guest == jit_env.code_mem_modified_by_guest); + if (uni_env.code_mem_modified_by_guest) { + return; + } + REQUIRE(uni.GetPC() == jit.GetPC()); REQUIRE(uni.GetRegisters() == jit.GetRegisters()); REQUIRE(uni.GetVectors() == jit.GetVectors()); REQUIRE(uni.GetSP() == jit.GetSP()); REQUIRE((uni.GetPstate() & 0xF0000000) == (jit.GetPstate() & 0xF0000000)); REQUIRE(uni_env.modified_memory == jit_env.modified_memory); + REQUIRE(uni_env.interrupts.empty()); } TEST_CASE("A64: Single random instruction", "[a64]") { diff --git a/tests/A64/testenv.h b/tests/A64/testenv.h index 15bc1f1a..10a32b05 100644 --- a/tests/A64/testenv.h +++ b/tests/A64/testenv.h @@ -22,6 +22,7 @@ public: bool code_mem_modified_by_guest = false; std::array code_mem{}; std::map modified_memory; + std::vector interrupts; std::uint32_t MemoryReadCode(u64 vaddr) override { if (vaddr < code_mem.size() * sizeof(u32)) { diff --git a/tests/A64/unicorn_emu/unicorn.cpp b/tests/A64/unicorn_emu/unicorn.cpp index 3e377075..4eb2a6ac 100644 --- a/tests/A64/unicorn_emu/unicorn.cpp +++ b/tests/A64/unicorn_emu/unicorn.cpp @@ -38,6 +38,9 @@ void Unicorn::Run() { while (testenv.ticks_left > 0) { CHECKED(uc_emu_start(uc, GetPC(), END_ADDRESS, 0, 1)); testenv.ticks_left--; + if (!testenv.interrupts.empty() || testenv.code_mem_modified_by_guest) { + return; + } } } @@ -168,7 +171,8 @@ void Unicorn::InterruptHook(uc_engine* uc, u32 int_number, void* user_data) { this_->testenv.CallSVC(iss); break; default: - ASSERT_MSG(false, "Unhandled interrupt: int_number: {:#x}, esr: {:#x} (ec: {:#x}, iss: {:#x})", int_number, esr, ec, iss); + this_->testenv.interrupts.emplace_back(fmt::format("Unhandled interrupt: int_number: {:#x}, esr: {:#x} (ec: {:#x}, iss: {:#x})", int_number, esr, ec, iss)); + break; } }