backend: Unify exception handlers across architectures
This commit is contained in:
parent
46e5f4ee97
commit
c72ee5473b
5 changed files with 139 additions and 59 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@ cmake-build-*/
|
||||||
.idea/
|
.idea/
|
||||||
docs/Doxygen/
|
docs/Doxygen/
|
||||||
# Generated files
|
# Generated files
|
||||||
|
src/dynarmic/backend/arm64/mig/
|
||||||
src/dynarmic/backend/x64/mig/
|
src/dynarmic/backend/x64/mig/
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -330,41 +330,6 @@ if (ARCHITECTURE STREQUAL "x86_64")
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
target_sources(dynarmic PRIVATE backend/x64/exception_handler_windows.cpp)
|
|
||||||
elseif (APPLE)
|
|
||||||
find_path(MACH_EXC_DEFS_DIR "mach/mach_exc.defs")
|
|
||||||
if (NOT MACH_EXC_DEFS_DIR)
|
|
||||||
message(WARNING "macOS fastmem disabled: unable to find mach/mach_exc.defs")
|
|
||||||
target_sources(dynarmic PRIVATE backend/exception_handler_generic.cpp)
|
|
||||||
else()
|
|
||||||
message(STATUS "mach/mach_exc.defs location: ${MACH_EXC_DEFS_DIR}")
|
|
||||||
execute_process(
|
|
||||||
COMMAND
|
|
||||||
mkdir -p "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig"
|
|
||||||
COMMAND
|
|
||||||
mig
|
|
||||||
-arch x86_64
|
|
||||||
-user "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_user.c"
|
|
||||||
-header "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_user.h"
|
|
||||||
-server "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_server.c"
|
|
||||||
-sheader "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_server.h"
|
|
||||||
"${MACH_EXC_DEFS_DIR}/mach/mach_exc.defs"
|
|
||||||
)
|
|
||||||
target_sources(dynarmic PRIVATE
|
|
||||||
backend/x64/exception_handler_macos.cpp
|
|
||||||
backend/x64/mig/mach_exc_server.c
|
|
||||||
backend/x64/mig/mach_exc_server.h
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
elseif (UNIX)
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
||||||
target_link_libraries(dynarmic PRIVATE rt)
|
|
||||||
endif()
|
|
||||||
target_sources(dynarmic PRIVATE backend/exception_handler_posix.cpp)
|
|
||||||
else()
|
|
||||||
target_sources(dynarmic PRIVATE backend/exception_handler_generic.cpp)
|
|
||||||
endif()
|
|
||||||
elseif(ARCHITECTURE STREQUAL "arm64")
|
elseif(ARCHITECTURE STREQUAL "arm64")
|
||||||
target_link_libraries(dynarmic PRIVATE merry::oaknut)
|
target_link_libraries(dynarmic PRIVATE merry::oaknut)
|
||||||
|
|
||||||
|
@ -423,17 +388,54 @@ elseif(ARCHITECTURE STREQUAL "arm64")
|
||||||
backend/arm64/a64_interface.cpp
|
backend/arm64/a64_interface.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if (UNIX)
|
if (WIN32)
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
target_sources(dynarmic PRIVATE backend/exception_handler_windows.cpp)
|
||||||
target_link_libraries(dynarmic PRIVATE rt)
|
elseif (APPLE)
|
||||||
endif()
|
find_path(MACH_EXC_DEFS_DIR "mach/mach_exc.defs")
|
||||||
target_sources(dynarmic PRIVATE backend/exception_handler_posix.cpp)
|
if (NOT MACH_EXC_DEFS_DIR)
|
||||||
else()
|
message(WARNING "macOS fastmem disabled: unable to find mach/mach_exc.defs")
|
||||||
target_sources(dynarmic PRIVATE backend/exception_handler_generic.cpp)
|
target_sources(dynarmic PRIVATE backend/exception_handler_generic.cpp)
|
||||||
|
else()
|
||||||
|
message(STATUS "mach/mach_exc.defs location: ${MACH_EXC_DEFS_DIR}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
mkdir -p "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig"
|
||||||
|
COMMAND
|
||||||
|
mig
|
||||||
|
-arch x86_64
|
||||||
|
-user "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_user.c"
|
||||||
|
-header "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_user.h"
|
||||||
|
-server "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_server.c"
|
||||||
|
-sheader "${CMAKE_CURRENT_SOURCE_DIR}/backend/x64/mig/mach_exc_server.h"
|
||||||
|
"${MACH_EXC_DEFS_DIR}/mach/mach_exc.defs"
|
||||||
|
)
|
||||||
|
message(STATUS "mach/mach_exc.defs location: ${MACH_EXC_DEFS_DIR}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
mkdir -p "${CMAKE_CURRENT_SOURCE_DIR}/backend/arm64/mig"
|
||||||
|
COMMAND
|
||||||
|
mig
|
||||||
|
-arch arm64
|
||||||
|
-user "${CMAKE_CURRENT_SOURCE_DIR}/backend/arm64/mig/mach_exc_user.c"
|
||||||
|
-header "${CMAKE_CURRENT_SOURCE_DIR}/backend/arm64/mig/mach_exc_user.h"
|
||||||
|
-server "${CMAKE_CURRENT_SOURCE_DIR}/backend/arm64/mig/mach_exc_server.c"
|
||||||
|
-sheader "${CMAKE_CURRENT_SOURCE_DIR}/backend/arm64/mig/mach_exc_server.h"
|
||||||
|
"${MACH_EXC_DEFS_DIR}/mach/mach_exc.defs"
|
||||||
|
)
|
||||||
|
target_sources(dynarmic PRIVATE
|
||||||
|
backend/exception_handler_macos.cpp
|
||||||
|
backend/exception_handler_macos_mig.c
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
elseif (UNIX)
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
target_link_libraries(dynarmic PRIVATE rt)
|
||||||
|
endif()
|
||||||
|
target_sources(dynarmic PRIVATE backend/exception_handler_posix.cpp)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported architecture")
|
target_sources(dynarmic PRIVATE backend/exception_handler_generic.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CreateDirectoryGroups)
|
include(CreateDirectoryGroups)
|
||||||
|
|
|
@ -16,18 +16,37 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mcl/assert.hpp>
|
#include <mcl/assert.hpp>
|
||||||
#include <mcl/bit_cast.hpp>
|
#include <mcl/bit_cast.hpp>
|
||||||
|
#include <mcl/macro/architecture.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
|
|
||||||
#include "dynarmic/backend/exception_handler.h"
|
#include "dynarmic/backend/exception_handler.h"
|
||||||
#include "dynarmic/backend/x64/block_of_code.h"
|
|
||||||
|
|
||||||
#define mig_external extern "C"
|
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||||
#include "dynarmic/backend/x64/mig/mach_exc_server.h"
|
|
||||||
|
# include "dynarmic/backend/x64/block_of_code.h"
|
||||||
|
# define mig_external extern "C"
|
||||||
|
# include "dynarmic/backend/x64/mig/mach_exc_server.h"
|
||||||
|
|
||||||
|
# define THREAD_STATE x86_THREAD_STATE64
|
||||||
|
# define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
|
||||||
|
|
||||||
|
using dynarmic_thread_state_t = x86_thread_state64_t;
|
||||||
|
|
||||||
|
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||||
|
|
||||||
|
# include <oaknut/code_block.hpp>
|
||||||
|
# define mig_external extern "C"
|
||||||
|
# include "dynarmic/backend/arm64/mig/mach_exc_server.h"
|
||||||
|
|
||||||
|
# define THREAD_STATE ARM_THREAD_STATE64
|
||||||
|
# define THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
|
||||||
|
|
||||||
|
using dynarmic_thread_state_t = arm_thread_state64_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Dynarmic::Backend {
|
namespace Dynarmic::Backend {
|
||||||
|
|
||||||
using namespace Dynarmic::Backend::X64;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct CodeBlockInfo {
|
struct CodeBlockInfo {
|
||||||
|
@ -45,7 +64,7 @@ public:
|
||||||
MachHandler();
|
MachHandler();
|
||||||
~MachHandler();
|
~MachHandler();
|
||||||
|
|
||||||
kern_return_t HandleRequest(x86_thread_state64_t* thread_state);
|
kern_return_t HandleRequest(dynarmic_thread_state_t* thread_state);
|
||||||
|
|
||||||
void AddCodeBlock(CodeBlockInfo info);
|
void AddCodeBlock(CodeBlockInfo info);
|
||||||
void RemoveCodeBlock(u64 rip);
|
void RemoveCodeBlock(u64 rip);
|
||||||
|
@ -69,7 +88,7 @@ MachHandler::MachHandler() {
|
||||||
|
|
||||||
KCHECK(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port));
|
KCHECK(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port));
|
||||||
KCHECK(mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND));
|
KCHECK(mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND));
|
||||||
KCHECK(task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, server_port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, x86_THREAD_STATE64));
|
KCHECK(task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, server_port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE));
|
||||||
|
|
||||||
// The below doesn't actually work, and I'm not sure why; since this doesn't work we'll have a spurious error message upon shutdown.
|
// The below doesn't actually work, and I'm not sure why; since this doesn't work we'll have a spurious error message upon shutdown.
|
||||||
mach_port_t prev;
|
mach_port_t prev;
|
||||||
|
@ -110,6 +129,7 @@ void MachHandler::MessagePump() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||||
kern_return_t MachHandler::HandleRequest(x86_thread_state64_t* ts) {
|
kern_return_t MachHandler::HandleRequest(x86_thread_state64_t* ts) {
|
||||||
std::lock_guard<std::mutex> guard(code_block_infos_mutex);
|
std::lock_guard<std::mutex> guard(code_block_infos_mutex);
|
||||||
|
|
||||||
|
@ -127,6 +147,24 @@ kern_return_t MachHandler::HandleRequest(x86_thread_state64_t* ts) {
|
||||||
|
|
||||||
return KERN_SUCCESS;
|
return KERN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||||
|
kern_return_t MachHandler::HandleRequest(arm_thread_state64_t* ts) {
|
||||||
|
std::lock_guard<std::mutex> guard(code_block_infos_mutex);
|
||||||
|
|
||||||
|
const auto iter = FindCodeBlockInfo(ts->__pc);
|
||||||
|
if (iter == code_block_infos.end()) {
|
||||||
|
fmt::print(stderr, "Unhandled EXC_BAD_ACCESS at pc {:#016x}\n", ts->__pc);
|
||||||
|
return KERN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeCall fc = iter->cb(ts->__pc);
|
||||||
|
|
||||||
|
// TODO: Sign with ptrauth_sign_unauthenticated if pointer authentication is enabled.
|
||||||
|
ts->__pc = fc.call_pc;
|
||||||
|
|
||||||
|
return KERN_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void MachHandler::AddCodeBlock(CodeBlockInfo cbi) {
|
void MachHandler::AddCodeBlock(CodeBlockInfo cbi) {
|
||||||
std::lock_guard<std::mutex> guard(code_block_infos_mutex);
|
std::lock_guard<std::mutex> guard(code_block_infos_mutex);
|
||||||
|
@ -173,7 +211,7 @@ mig_external kern_return_t catch_mach_exception_raise_state(
|
||||||
fmt::print(stderr, "dynarmic: catch_mach_exception_raise_state: Invalid arguments.\n");
|
fmt::print(stderr, "dynarmic: catch_mach_exception_raise_state: Invalid arguments.\n");
|
||||||
return KERN_INVALID_ARGUMENT;
|
return KERN_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
if (*flavor != x86_THREAD_STATE64 || old_stateCnt != x86_THREAD_STATE64_COUNT || *new_stateCnt < x86_THREAD_STATE64_COUNT) {
|
if (*flavor != THREAD_STATE || old_stateCnt != THREAD_STATE_COUNT || *new_stateCnt < THREAD_STATE_COUNT) {
|
||||||
fmt::print(stderr, "dynarmic: catch_mach_exception_raise_state: Unexpected flavor.\n");
|
fmt::print(stderr, "dynarmic: catch_mach_exception_raise_state: Unexpected flavor.\n");
|
||||||
return KERN_INVALID_ARGUMENT;
|
return KERN_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
@ -182,17 +220,17 @@ mig_external kern_return_t catch_mach_exception_raise_state(
|
||||||
return KERN_FAILURE;
|
return KERN_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
x86_thread_state64_t* ts = reinterpret_cast<x86_thread_state64_t*>(new_state);
|
dynarmic_thread_state_t* ts = reinterpret_cast<dynarmic_thread_state_t*>(new_state);
|
||||||
std::memcpy(ts, reinterpret_cast<const x86_thread_state64_t*>(old_state), sizeof(x86_thread_state64_t));
|
std::memcpy(ts, reinterpret_cast<const dynarmic_thread_state_t*>(old_state), sizeof(dynarmic_thread_state_t));
|
||||||
*new_stateCnt = x86_THREAD_STATE64_COUNT;
|
*new_stateCnt = THREAD_STATE_COUNT;
|
||||||
|
|
||||||
return mach_handler.HandleRequest(ts);
|
return mach_handler.HandleRequest(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExceptionHandler::Impl final {
|
struct ExceptionHandler::Impl final {
|
||||||
Impl(BlockOfCode& code)
|
Impl(u64 code_begin_, u64 code_end_)
|
||||||
: code_begin(mcl::bit_cast<u64>(code.getCode()))
|
: code_begin(code_begin_)
|
||||||
, code_end(code_begin + code.GetTotalCodeSize()) {}
|
, code_end(code_end_) {}
|
||||||
|
|
||||||
void SetCallback(std::function<FakeCall(u64)> cb) {
|
void SetCallback(std::function<FakeCall(u64)> cb) {
|
||||||
CodeBlockInfo cbi;
|
CodeBlockInfo cbi;
|
||||||
|
@ -211,12 +249,23 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
ExceptionHandler::ExceptionHandler() = default;
|
ExceptionHandler::ExceptionHandler() = default;
|
||||||
|
|
||||||
ExceptionHandler::~ExceptionHandler() = default;
|
ExceptionHandler::~ExceptionHandler() = default;
|
||||||
|
|
||||||
void ExceptionHandler::Register(BlockOfCode& code) {
|
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||||
impl = std::make_unique<Impl>(code);
|
void ExceptionHandler::Register(X64::BlockOfCode& code) {
|
||||||
|
const u64 code_begin = mcl::bit_cast<u64>(code.getCode());
|
||||||
|
const u64 code_end = code_begin + code.GetTotalCodeSize();
|
||||||
|
impl = std::make_unique<Impl>(code_begin, code_end);
|
||||||
}
|
}
|
||||||
|
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||||
|
void ExceptionHandler::Register(oaknut::CodeBlock& mem, std::size_t size) {
|
||||||
|
const u64 code_begin = mcl::bit_cast<u64>(mem.ptr());
|
||||||
|
const u64 code_end = code_begin + size;
|
||||||
|
impl = std::make_unique<Impl>(code_begin, code_end);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "Invalid architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
bool ExceptionHandler::SupportsFastmem() const noexcept {
|
||||||
return static_cast<bool>(impl);
|
return static_cast<bool>(impl);
|
14
src/dynarmic/backend/exception_handler_macos_mig.c
Normal file
14
src/dynarmic/backend/exception_handler_macos_mig.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2023 MerryMage
|
||||||
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mcl/macro/architecture.hpp>
|
||||||
|
|
||||||
|
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||||
|
# include "dynarmic/backend/x64/mig/mach_exc_server.c"
|
||||||
|
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||||
|
# include "dynarmic/backend/arm64/mig/mach_exc_server.c"
|
||||||
|
#else
|
||||||
|
# error "Invalid architecture"
|
||||||
|
#endif
|
14
src/dynarmic/backend/exception_handler_windows.cpp
Normal file
14
src/dynarmic/backend/exception_handler_windows.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2023 MerryMage
|
||||||
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <mcl/macro/architecture.hpp>
|
||||||
|
|
||||||
|
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||||
|
# include "dynarmic/backend/x64/exception_handler_windows.cpp"
|
||||||
|
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||||
|
# include "dynarmic/backend/exception_handler_generic.cpp"
|
||||||
|
#else
|
||||||
|
# error "Invalid architecture"
|
||||||
|
#endif
|
Loading…
Reference in a new issue