backend/x64: Add fastmem support to Windows exception handler
This commit is contained in:
parent
b7b71d65c2
commit
4e83e81e58
1 changed files with 62 additions and 28 deletions
|
@ -13,6 +13,7 @@
|
||||||
#include "backend/x64/block_of_code.h"
|
#include "backend/x64/block_of_code.h"
|
||||||
#include "backend/x64/exception_handler.h"
|
#include "backend/x64/exception_handler.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/cast_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
using UBYTE = u8;
|
using UBYTE = u8;
|
||||||
|
@ -67,6 +68,12 @@ struct UNWIND_INFO {
|
||||||
UBYTE FrameOffset : 4;
|
UBYTE FrameOffset : 4;
|
||||||
// UNWIND_CODE UnwindCode[];
|
// UNWIND_CODE UnwindCode[];
|
||||||
// With Flags == 0 there are no additional fields.
|
// With Flags == 0 there are no additional fields.
|
||||||
|
// OPTIONAL UNW_EXCEPTION_INFO ExceptionInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UNW_EXCEPTION_INFO {
|
||||||
|
ULONG ExceptionHandler;
|
||||||
|
// OPTIONAL ARBITRARY HandlerData;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend::X64 {
|
||||||
|
@ -158,28 +165,32 @@ static PrologueInformation GetPrologueInformation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExceptionHandler::Impl final {
|
struct ExceptionHandler::Impl final {
|
||||||
Impl(RUNTIME_FUNCTION* rfuncs_, const u8* base_ptr) : rfuncs(rfuncs_) {
|
Impl(BlockOfCode& code) {
|
||||||
RtlAddFunctionTable(rfuncs, 1, reinterpret_cast<DWORD64>(base_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
~Impl() {
|
|
||||||
RtlDeleteFunctionTable(rfuncs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RUNTIME_FUNCTION* rfuncs = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
ExceptionHandler::ExceptionHandler() = default;
|
|
||||||
ExceptionHandler::~ExceptionHandler() = default;
|
|
||||||
|
|
||||||
void ExceptionHandler::Register(BlockOfCode& code) {
|
|
||||||
const auto prolog_info = GetPrologueInformation();
|
const auto prolog_info = GetPrologueInformation();
|
||||||
|
|
||||||
|
code.align(16);
|
||||||
|
const u8* exception_handler = code.getCurr<u8*>();
|
||||||
|
// Our 3rd argument is a PCONTEXT.
|
||||||
|
code.sub(code.rsp, 8);
|
||||||
|
code.mov(code.ABI_PARAM1, Common::BitCast<u64>(&cb));
|
||||||
|
code.mov(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||||
|
code.CallLambda(
|
||||||
|
[](const std::function<FakeCall(u64)>& cb_, PCONTEXT ctx){
|
||||||
|
FakeCall fc = cb_(ctx->Rip);
|
||||||
|
|
||||||
|
ctx->Rsp -= sizeof(u64);
|
||||||
|
*Common::BitCast<u64*>(ctx->Rsp) = fc.ret_rip;
|
||||||
|
ctx->Rip = fc.call_rip;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
code.add(code.rsp, 8);
|
||||||
|
code.mov(code.eax, static_cast<u32>(ExceptionContinueExecution));
|
||||||
|
code.ret();
|
||||||
|
|
||||||
code.align(16);
|
code.align(16);
|
||||||
UNWIND_INFO* unwind_info = static_cast<UNWIND_INFO*>(code.AllocateFromCodeSpace(sizeof(UNWIND_INFO)));
|
UNWIND_INFO* unwind_info = static_cast<UNWIND_INFO*>(code.AllocateFromCodeSpace(sizeof(UNWIND_INFO)));
|
||||||
unwind_info->Version = 1;
|
unwind_info->Version = 1;
|
||||||
unwind_info->Flags = 0; // No special exception handling required.
|
unwind_info->Flags = UNW_FLAG_EHANDLER;
|
||||||
unwind_info->SizeOfProlog = prolog_info.prolog_size;
|
unwind_info->SizeOfProlog = prolog_info.prolog_size;
|
||||||
unwind_info->CountOfCodes = static_cast<UBYTE>(prolog_info.number_of_unwind_code_entries);
|
unwind_info->CountOfCodes = static_cast<UBYTE>(prolog_info.number_of_unwind_code_entries);
|
||||||
unwind_info->FrameRegister = 0; // No frame register present
|
unwind_info->FrameRegister = 0; // No frame register present
|
||||||
|
@ -188,22 +199,45 @@ void ExceptionHandler::Register(BlockOfCode& code) {
|
||||||
const size_t size_of_unwind_code = sizeof(UNWIND_CODE) * prolog_info.unwind_code.size();
|
const size_t size_of_unwind_code = sizeof(UNWIND_CODE) * prolog_info.unwind_code.size();
|
||||||
UNWIND_CODE* unwind_code = static_cast<UNWIND_CODE*>(code.AllocateFromCodeSpace(size_of_unwind_code));
|
UNWIND_CODE* unwind_code = static_cast<UNWIND_CODE*>(code.AllocateFromCodeSpace(size_of_unwind_code));
|
||||||
memcpy(unwind_code, prolog_info.unwind_code.data(), size_of_unwind_code);
|
memcpy(unwind_code, prolog_info.unwind_code.data(), size_of_unwind_code);
|
||||||
|
// UNWIND_INFO::ExceptionInfo field:
|
||||||
|
UNW_EXCEPTION_INFO* except_info = static_cast<UNW_EXCEPTION_INFO*>(code.AllocateFromCodeSpace(sizeof(UNW_EXCEPTION_INFO)));
|
||||||
|
except_info->ExceptionHandler = static_cast<ULONG>(exception_handler - code.getCode<u8*>());
|
||||||
|
|
||||||
code.align(16);
|
code.align(16);
|
||||||
RUNTIME_FUNCTION* rfuncs = static_cast<RUNTIME_FUNCTION*>(code.AllocateFromCodeSpace(sizeof(RUNTIME_FUNCTION)));
|
rfuncs = static_cast<RUNTIME_FUNCTION*>(code.AllocateFromCodeSpace(sizeof(RUNTIME_FUNCTION)));
|
||||||
rfuncs->BeginAddress = static_cast<DWORD>(0);
|
rfuncs->BeginAddress = static_cast<DWORD>(0);
|
||||||
rfuncs->EndAddress = static_cast<DWORD>(code.GetTotalCodeSize());
|
rfuncs->EndAddress = static_cast<DWORD>(code.GetTotalCodeSize());
|
||||||
rfuncs->UnwindData = static_cast<DWORD>(reinterpret_cast<u8*>(unwind_info) - code.getCode());
|
rfuncs->UnwindData = static_cast<DWORD>(reinterpret_cast<u8*>(unwind_info) - code.getCode());
|
||||||
|
|
||||||
impl = std::make_unique<Impl>(rfuncs, code.getCode());
|
RtlAddFunctionTable(rfuncs, 1, reinterpret_cast<DWORD64>(code.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCallback(std::function<FakeCall(u64)> new_cb) {
|
||||||
|
cb = new_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Impl() {
|
||||||
|
RtlDeleteFunctionTable(rfuncs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RUNTIME_FUNCTION* rfuncs;
|
||||||
|
std::function<FakeCall(u64)> cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExceptionHandler::ExceptionHandler() = default;
|
||||||
|
ExceptionHandler::~ExceptionHandler() = default;
|
||||||
|
|
||||||
|
void ExceptionHandler::Register(BlockOfCode& code) {
|
||||||
|
impl = std::make_unique<Impl>(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
||||||
return false;
|
return static_cast<bool>(impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionHandler::SetFastmemCallback(std::function<FakeCall(u64)>) {
|
void ExceptionHandler::SetFastmemCallback(std::function<FakeCall(u64)> cb) {
|
||||||
// Do nothing
|
impl->SetCallback(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::X64
|
} // namespace Dynarmic::Backend::X64
|
||||||
|
|
Loading…
Reference in a new issue