mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Add a test for unhandled exceptions (#493)
This commit is contained in:
@@ -622,6 +622,23 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
bool test_unhandled_exception()
|
||||
{
|
||||
thread_local bool caught{};
|
||||
caught = false;
|
||||
|
||||
auto* old = SetUnhandledExceptionFilter(+[](struct _EXCEPTION_POINTERS* ExceptionInfo) -> LONG {
|
||||
caught = true;
|
||||
ExceptionInfo->ContextRecord->Rip += 1;
|
||||
return EXCEPTION_CONTINUE_EXECUTION; //
|
||||
});
|
||||
|
||||
DebugBreak();
|
||||
SetUnhandledExceptionFilter(old);
|
||||
|
||||
return caught;
|
||||
}
|
||||
|
||||
bool test_illegal_instruction_exception()
|
||||
{
|
||||
const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
@@ -737,7 +754,10 @@ namespace
|
||||
|
||||
bool test_native_exceptions()
|
||||
{
|
||||
return test_access_violation_exception() && test_illegal_instruction_exception() && test_guard_page_exception();
|
||||
return test_access_violation_exception() //
|
||||
&& test_illegal_instruction_exception() //
|
||||
&& test_unhandled_exception() //
|
||||
&& test_guard_page_exception();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "exception_dispatch.hpp"
|
||||
#include "process_context.hpp"
|
||||
#include "cpu_context.hpp"
|
||||
#include "windows_emulator.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -136,19 +137,19 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const DWORD status,
|
||||
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
|
||||
void dispatch_exception(windows_emulator& win_emu, const DWORD status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
|
||||
{
|
||||
CONTEXT64 ctx{};
|
||||
ctx.ContextFlags = CONTEXT64_ALL;
|
||||
cpu_context::save(emu, ctx);
|
||||
cpu_context::save(win_emu.emu(), ctx);
|
||||
ctx.Rip = win_emu.current_thread().current_ip;
|
||||
|
||||
exception_record record{};
|
||||
memset(&record, 0, sizeof(record));
|
||||
record.ExceptionCode = status;
|
||||
record.ExceptionFlags = 0;
|
||||
record.ExceptionRecord = 0;
|
||||
record.ExceptionAddress = emu.read_instruction_pointer();
|
||||
record.ExceptionAddress = ctx.Rip;
|
||||
record.NumberParameters = static_cast<DWORD>(parameters.size());
|
||||
|
||||
if (parameters.size() > 15)
|
||||
@@ -165,44 +166,43 @@ void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const
|
||||
pointers.ContextRecord = reinterpret_cast<EmulatorTraits<Emu64>::PVOID>(&ctx);
|
||||
pointers.ExceptionRecord = reinterpret_cast<EmulatorTraits<Emu64>::PVOID>(&record);
|
||||
|
||||
dispatch_exception_pointers(emu, proc.ki_user_exception_dispatcher, pointers);
|
||||
dispatch_exception_pointers(win_emu.emu(), win_emu.process.ki_user_exception_dispatcher, pointers);
|
||||
}
|
||||
|
||||
void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc, const uint64_t address, const memory_operation operation)
|
||||
void dispatch_access_violation(windows_emulator& win_emu, const uint64_t address, const memory_operation operation)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_ACCESS_VIOLATION,
|
||||
dispatch_exception(win_emu, STATUS_ACCESS_VIOLATION,
|
||||
{
|
||||
map_violation_operation_to_parameter(operation),
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, const uint64_t address,
|
||||
const memory_operation operation)
|
||||
void dispatch_guard_page_violation(windows_emulator& win_emu, const uint64_t address, const memory_operation operation)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_GUARD_PAGE_VIOLATION,
|
||||
dispatch_exception(win_emu, STATUS_GUARD_PAGE_VIOLATION,
|
||||
{
|
||||
map_violation_operation_to_parameter(operation),
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc)
|
||||
void dispatch_illegal_instruction_violation(windows_emulator& win_emu)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_ILLEGAL_INSTRUCTION, {});
|
||||
dispatch_exception(win_emu, STATUS_ILLEGAL_INSTRUCTION, {});
|
||||
}
|
||||
|
||||
void dispatch_integer_division_by_zero(x86_64_emulator& emu, const process_context& proc)
|
||||
void dispatch_integer_division_by_zero(windows_emulator& win_emu)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_INTEGER_DIVIDE_BY_ZERO, {});
|
||||
dispatch_exception(win_emu, STATUS_INTEGER_DIVIDE_BY_ZERO, {});
|
||||
}
|
||||
|
||||
void dispatch_single_step(x86_64_emulator& emu, const process_context& proc)
|
||||
void dispatch_single_step(windows_emulator& win_emu)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_SINGLE_STEP, {});
|
||||
dispatch_exception(win_emu, STATUS_SINGLE_STEP, {});
|
||||
}
|
||||
|
||||
void dispatch_breakpoint(x86_64_emulator& emu, const process_context& proc)
|
||||
void dispatch_breakpoint(windows_emulator& win_emu)
|
||||
{
|
||||
dispatch_exception(emu, proc, STATUS_BREAKPOINT, {});
|
||||
dispatch_exception(win_emu, STATUS_BREAKPOINT, {});
|
||||
}
|
||||
|
||||
@@ -5,21 +5,19 @@
|
||||
#include <platform/traits.hpp>
|
||||
#include <platform/primitives.hpp>
|
||||
|
||||
struct process_context;
|
||||
class windows_emulator;
|
||||
|
||||
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, DWORD status,
|
||||
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters);
|
||||
void dispatch_exception(windows_emulator& win_emu, DWORD status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters);
|
||||
template <typename T>
|
||||
requires(std::is_integral_v<T> && !std::is_same_v<T, DWORD>)
|
||||
void dispatch_exception(x86_64_emulator& emu, const process_context& proc, const T status,
|
||||
const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
|
||||
void dispatch_exception(windows_emulator& win_emu, const T status, const std::vector<EmulatorTraits<Emu64>::ULONG_PTR>& parameters)
|
||||
{
|
||||
dispatch_exception(emu, proc, static_cast<DWORD>(status), parameters);
|
||||
dispatch_exception(win_emu, static_cast<DWORD>(status), parameters);
|
||||
}
|
||||
|
||||
void dispatch_access_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address, memory_operation operation);
|
||||
void dispatch_guard_page_violation(x86_64_emulator& emu, const process_context& proc, uint64_t address, memory_operation operation);
|
||||
void dispatch_illegal_instruction_violation(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_integer_division_by_zero(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_single_step(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_breakpoint(x86_64_emulator& emu, const process_context& proc);
|
||||
void dispatch_access_violation(windows_emulator& win_emu, uint64_t address, memory_operation operation);
|
||||
void dispatch_guard_page_violation(windows_emulator& win_emu, uint64_t address, memory_operation operation);
|
||||
void dispatch_illegal_instruction_violation(windows_emulator& win_emu);
|
||||
void dispatch_integer_division_by_zero(windows_emulator& win_emu);
|
||||
void dispatch_single_step(windows_emulator& win_emu);
|
||||
void dispatch_breakpoint(windows_emulator& win_emu);
|
||||
|
||||
@@ -466,7 +466,7 @@ void windows_emulator::setup_hooks()
|
||||
// TODO: Unicorn needs this - This should be handled in the backend
|
||||
this->emu().hook_instruction(x86_hookable_instructions::invalid, [&] {
|
||||
// TODO: Unify icicle & unicorn handling
|
||||
dispatch_illegal_instruction_violation(this->emu(), this->process);
|
||||
dispatch_illegal_instruction_violation(*this);
|
||||
return instruction_hook_continuation::skip_instruction; //
|
||||
});
|
||||
|
||||
@@ -477,7 +477,7 @@ void windows_emulator::setup_hooks()
|
||||
switch (interrupt)
|
||||
{
|
||||
case 0:
|
||||
dispatch_integer_division_by_zero(this->emu(), this->process);
|
||||
dispatch_integer_division_by_zero(*this);
|
||||
return;
|
||||
case 1:
|
||||
if ((eflags & 0x100) != 0)
|
||||
@@ -486,19 +486,19 @@ void windows_emulator::setup_hooks()
|
||||
}
|
||||
|
||||
this->callbacks.on_suspicious_activity("Singlestep");
|
||||
dispatch_single_step(this->emu(), this->process);
|
||||
dispatch_single_step(*this);
|
||||
return;
|
||||
case 3:
|
||||
this->callbacks.on_suspicious_activity("Breakpoint");
|
||||
dispatch_breakpoint(this->emu(), this->process);
|
||||
dispatch_breakpoint(*this);
|
||||
return;
|
||||
case 6:
|
||||
this->callbacks.on_suspicious_activity("Illegal instruction");
|
||||
dispatch_illegal_instruction_violation(this->emu(), this->process);
|
||||
dispatch_illegal_instruction_violation(*this);
|
||||
return;
|
||||
case 45:
|
||||
this->callbacks.on_suspicious_activity("DbgPrint");
|
||||
dispatch_breakpoint(this->emu(), this->process);
|
||||
dispatch_breakpoint(*this);
|
||||
return;
|
||||
default:
|
||||
if (this->callbacks.on_generic_activity)
|
||||
@@ -517,12 +517,12 @@ void windows_emulator::setup_hooks()
|
||||
{
|
||||
// Unset the GUARD_PAGE flag and dispatch a STATUS_GUARD_PAGE_VIOLATION
|
||||
this->memory.protect_memory(region.allocation_base, region.length, region.permissions & ~memory_permission_ext::guard);
|
||||
dispatch_guard_page_violation(this->emu(), this->process, address, operation);
|
||||
dispatch_guard_page_violation(*this, address, operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->callbacks.on_memory_violate(address, size, operation, type);
|
||||
dispatch_access_violation(this->emu(), this->process, address, operation);
|
||||
dispatch_access_violation(*this, address, operation);
|
||||
}
|
||||
|
||||
return memory_violation_continuation::resume;
|
||||
|
||||
Reference in New Issue
Block a user