From b2b2ffd6be969bcba07965e5f8c429483756cf2d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 11 Jan 2025 09:51:22 +0100 Subject: [PATCH] Cleanup exception handling and prepare UI support --- src/common/platform/status.hpp | 15 ++--- src/windows-emulator/syscalls.cpp | 18 ++++++ src/windows-emulator/windows_emulator.cpp | 67 ++++++++++++++--------- 3 files changed, 67 insertions(+), 33 deletions(-) diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index ceecb0d9..9469bce4 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -5,15 +5,16 @@ using NTSTATUS = std::uint32_t; #ifndef OS_WINDOWS -#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L) -#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L) +#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L) +#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L) -#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L) -#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) -#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) -#define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS)0xC000001DL) +#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L) +#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS)0xC000001DL) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS)0xC0000094L) -#define STATUS_PENDING ((NTSTATUS)0x00000103L) +#define STATUS_PENDING ((NTSTATUS)0x00000103L) #endif #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index bf6775b8..df5e47f1 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -3198,6 +3198,21 @@ namespace return FALSE; } + NTSTATUS handle_NtUserGetDpiForCurrentProcess() + { + return 96; + } + + NTSTATUS handle_NtUserGetDCEx() + { + return 1; + } + + NTSTATUS handle_NtUserModifyUserStartupInfoFlags() + { + return STATUS_SUCCESS; + } + bool is_awaitable_object_type(const handle h) { return h.value.type == handle_types::thread // @@ -3510,6 +3525,9 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserSystemParametersInfo); add_handler(NtGetContextThread); add_handler(NtYieldExecution); + add_handler(NtUserModifyUserStartupInfoFlags); + add_handler(NtUserGetDCEx); + add_handler(NtUserGetDpiForCurrentProcess); #undef add_handler } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index a111148f..2b0bb14d 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -407,8 +407,10 @@ namespace }); } - void dispatch_access_violation(x64_emulator& emu, const uint64_t dispatcher, const uint64_t address, - const memory_operation operation) + template + requires(std::is_integral_v) + void dispatch_exception(x64_emulator& emu, const process_context& proc, const T status, + const std::vector::ULONG_PTR>& parameters) { CONTEXT64 ctx{}; ctx.ContextFlags = CONTEXT64_ALL; @@ -416,40 +418,47 @@ namespace EMU_EXCEPTION_RECORD> record{}; memset(&record, 0, sizeof(record)); - record.ExceptionCode = static_cast(STATUS_ACCESS_VIOLATION); + record.ExceptionCode = static_cast(status); record.ExceptionFlags = 0; record.ExceptionRecord = 0; - record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); - record.NumberParameters = 2; - record.ExceptionInformation[0] = map_violation_operation_to_parameter(operation); - record.ExceptionInformation[1] = address; + record.ExceptionAddress = emu.read_instruction_pointer(); + record.NumberParameters = static_cast(parameters.size()); + + if (parameters.size() > 15) + { + throw std::runtime_error("Too many exception parameters"); + } + + for (size_t i = 0; i < parameters.size(); ++i) + { + record.ExceptionInformation[i] = parameters[i]; + } EMU_EXCEPTION_POINTERS> pointers{}; pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); - dispatch_exception_pointers(emu, dispatcher, pointers); + dispatch_exception_pointers(emu, proc.ki_user_exception_dispatcher, pointers); } - void dispatch_illegal_instruction_violation(x64_emulator& emu, const uint64_t dispatcher) + void dispatch_access_violation(x64_emulator& emu, const process_context& proc, const uint64_t address, + const memory_operation operation) { - CONTEXT64 ctx{}; - ctx.ContextFlags = CONTEXT64_ALL; - context_frame::save(emu, ctx); + dispatch_exception(emu, proc, STATUS_ACCESS_VIOLATION, + { + map_violation_operation_to_parameter(operation), + address, + }); + } - EMU_EXCEPTION_RECORD> record{}; - memset(&record, 0, sizeof(record)); - record.ExceptionCode = static_cast(STATUS_ILLEGAL_INSTRUCTION); - record.ExceptionFlags = 0; - record.ExceptionRecord = 0; - record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); - record.NumberParameters = 0; + void dispatch_illegal_instruction_violation(x64_emulator& emu, const process_context& proc) + { + dispatch_exception(emu, proc, STATUS_ILLEGAL_INSTRUCTION, {}); + } - EMU_EXCEPTION_POINTERS> pointers{}; - pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); - pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); - - dispatch_exception_pointers(emu, dispatcher, pointers); + void dispatch_integer_division_by_zero(x64_emulator& emu, const process_context& proc) + { + dispatch_exception(emu, proc, STATUS_INTEGER_DIVIDE_BY_ZERO, {}); } void perform_context_switch_work(windows_emulator& win_emu) @@ -891,9 +900,15 @@ void windows_emulator::setup_hooks() }); this->emu().hook_interrupt([&](const int interrupt) { + if (interrupt == 0) + { + dispatch_integer_division_by_zero(this->emu(), this->process()); + return; + } + if (interrupt == 6) { - dispatch_illegal_instruction_violation(this->emu(), this->process().ki_user_exception_dispatcher); + dispatch_illegal_instruction_violation(this->emu(), this->process()); return; } @@ -931,7 +946,7 @@ void windows_emulator::setup_hooks() return memory_violation_continuation::stop; } - dispatch_access_violation(this->emu(), this->process().ki_user_exception_dispatcher, address, operation); + dispatch_access_violation(this->emu(), this->process(), address, operation); return memory_violation_continuation::resume; });