fuzz_with_unicorn: Avoid self-modifying code
* Don't immediately terminate when unicorn raises an interrupt * Detect self-modifying code
This commit is contained in:
parent
9f8c6f60f5
commit
9c4f234417
3 changed files with 22 additions and 4 deletions
|
@ -119,7 +119,7 @@ static u32 GenFloatInst(u64 pc, bool is_last_inst) {
|
||||||
// Approximation. Produces incorrect results.
|
// Approximation. Produces incorrect results.
|
||||||
"FMADD_float", "FMSUB_float", "FNMADD_float", "FNMSUB_float",
|
"FMADD_float", "FMSUB_float", "FNMADD_float", "FNMSUB_float",
|
||||||
// Requires investigation (temporarily disabled).
|
// Requires investigation (temporarily disabled).
|
||||||
"FDIV_2",
|
"FDIV_1", "FDIV_2",
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<InstructionGenerator> result;
|
std::vector<InstructionGenerator> 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,
|
static void RunTestInstance(const Unicorn::RegisterArray& regs, const Unicorn::VectorArray& vecs, const size_t instructions_offset,
|
||||||
const std::vector<u32>& instructions, const u32 pstate, const u32 fpcr) {
|
const std::vector<u32>& instructions, const u32 pstate, const u32 fpcr) {
|
||||||
static TestEnv jit_env;
|
static TestEnv jit_env{};
|
||||||
static TestEnv uni_env;
|
static TestEnv uni_env{};
|
||||||
|
|
||||||
std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + instructions_offset);
|
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);
|
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 .
|
uni_env.code_mem[instructions.size() + instructions_offset] = 0x14000000; // B .
|
||||||
jit_env.modified_memory.clear();
|
jit_env.modified_memory.clear();
|
||||||
uni_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};
|
Dynarmic::A64::UserConfig jit_user_config{&jit_env};
|
||||||
// The below corresponds to the settings for qemu's aarch64_max_initfn
|
// 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("x86_64:\n");
|
||||||
fmt::print("{}\n", jit.Disassemble());
|
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.GetPC() == jit.GetPC());
|
||||||
REQUIRE(uni.GetRegisters() == jit.GetRegisters());
|
REQUIRE(uni.GetRegisters() == jit.GetRegisters());
|
||||||
REQUIRE(uni.GetVectors() == jit.GetVectors());
|
REQUIRE(uni.GetVectors() == jit.GetVectors());
|
||||||
REQUIRE(uni.GetSP() == jit.GetSP());
|
REQUIRE(uni.GetSP() == jit.GetSP());
|
||||||
REQUIRE((uni.GetPstate() & 0xF0000000) == (jit.GetPstate() & 0xF0000000));
|
REQUIRE((uni.GetPstate() & 0xF0000000) == (jit.GetPstate() & 0xF0000000));
|
||||||
REQUIRE(uni_env.modified_memory == jit_env.modified_memory);
|
REQUIRE(uni_env.modified_memory == jit_env.modified_memory);
|
||||||
|
REQUIRE(uni_env.interrupts.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("A64: Single random instruction", "[a64]") {
|
TEST_CASE("A64: Single random instruction", "[a64]") {
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
bool code_mem_modified_by_guest = false;
|
bool code_mem_modified_by_guest = false;
|
||||||
std::array<u32, 1024> code_mem{};
|
std::array<u32, 1024> code_mem{};
|
||||||
std::map<u64, u8> modified_memory;
|
std::map<u64, u8> modified_memory;
|
||||||
|
std::vector<std::string> interrupts;
|
||||||
|
|
||||||
std::uint32_t MemoryReadCode(u64 vaddr) override {
|
std::uint32_t MemoryReadCode(u64 vaddr) override {
|
||||||
if (vaddr < code_mem.size() * sizeof(u32)) {
|
if (vaddr < code_mem.size() * sizeof(u32)) {
|
||||||
|
|
|
@ -38,6 +38,9 @@ void Unicorn::Run() {
|
||||||
while (testenv.ticks_left > 0) {
|
while (testenv.ticks_left > 0) {
|
||||||
CHECKED(uc_emu_start(uc, GetPC(), END_ADDRESS, 0, 1));
|
CHECKED(uc_emu_start(uc, GetPC(), END_ADDRESS, 0, 1));
|
||||||
testenv.ticks_left--;
|
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);
|
this_->testenv.CallSVC(iss);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue