mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
5 Commits
mach-excep
...
v2.5.411
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d6087f2a | ||
|
|
251962c415 | ||
|
|
1bdd7d2352 | ||
|
|
7b98259ea1 | ||
|
|
ee8166d1fe |
@@ -11,7 +11,6 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/WindowInfo.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
@@ -20,15 +19,12 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <thread>
|
||||
#include <time.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/thread_state.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mutex>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
@@ -298,7 +294,7 @@ static CPUInfo CalcCPUInfo()
|
||||
std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses();
|
||||
out.num_clusters = static_cast<u32>(classes.size());
|
||||
out.num_big_cores = classes.empty() ? 0 : classes[0].num_physical;
|
||||
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
|
||||
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
|
||||
out.num_small_cores = 0;
|
||||
for (std::size_t i = 1; i < classes.size(); i++)
|
||||
{
|
||||
@@ -572,206 +568,15 @@ void HostSys::EndCodeWrite()
|
||||
|
||||
#endif // _M_ARM64
|
||||
|
||||
#define USE_MACH_EXCEPTION_PORTS
|
||||
|
||||
namespace PageFaultHandler
|
||||
{
|
||||
#ifdef USE_MACH_EXCEPTION_PORTS
|
||||
static void SignalHandler(mach_port_t port);
|
||||
#else
|
||||
static void SignalHandler(int sig, siginfo_t* info, void* ctx);
|
||||
#endif
|
||||
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static bool s_in_exception_handler = false;
|
||||
static bool s_installed = false;
|
||||
} // namespace PageFaultHandler
|
||||
|
||||
#ifdef USE_MACH_EXCEPTION_PORTS
|
||||
|
||||
#if defined(_M_X86)
|
||||
#define THREAD_STATE64_COUNT x86_THREAD_STATE64_COUNT
|
||||
#define THREAD_STATE64 x86_THREAD_STATE64
|
||||
#define thread_state64_t x86_thread_state64_t
|
||||
#elif defined(_M_ARM64)
|
||||
#define THREAD_STATE64_COUNT ARM_THREAD_STATE64_COUNT
|
||||
#define THREAD_STATE64 ARM_THREAD_STATE64
|
||||
#define thread_state64_t arm_thread_state64_t
|
||||
#else
|
||||
#error Unknown Darwin Platform
|
||||
#endif
|
||||
|
||||
void PageFaultHandler::SignalHandler(mach_port_t port)
|
||||
{
|
||||
Threading::SetNameOfCurrentThread("Mach Exception Thread");
|
||||
|
||||
#pragma pack(4)
|
||||
struct
|
||||
{
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
exception_type_t exception;
|
||||
mach_msg_type_number_t codeCnt;
|
||||
int64_t code[2];
|
||||
int flavor;
|
||||
mach_msg_type_number_t old_stateCnt;
|
||||
natural_t old_state[THREAD_STATE64_COUNT];
|
||||
mach_msg_trailer_t trailer;
|
||||
} msg_in;
|
||||
|
||||
struct
|
||||
{
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
int flavor;
|
||||
mach_msg_type_number_t new_stateCnt;
|
||||
natural_t new_state[THREAD_STATE64_COUNT];
|
||||
} msg_out;
|
||||
#pragma pack()
|
||||
memset(&msg_in, 0xee, sizeof(msg_in));
|
||||
memset(&msg_out, 0xee, sizeof(msg_out));
|
||||
mach_msg_size_t send_size = 0;
|
||||
mach_msg_option_t option = MACH_RCV_MSG;
|
||||
while (true)
|
||||
{
|
||||
kern_return_t r;
|
||||
if ((r = mach_msg_overwrite(&msg_out.Head, option, send_size, sizeof(msg_in), port,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)))
|
||||
{
|
||||
pxFail(fmt::format("CRITICAL: mach_msg_overwrite: {:x}", r).c_str());
|
||||
}
|
||||
|
||||
if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS)
|
||||
{
|
||||
// the other thread exited
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_in.Head.msgh_id != 2406)
|
||||
{
|
||||
pxFailRel("unknown message received");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_in.flavor != THREAD_STATE64)
|
||||
{
|
||||
pxFailRel(fmt::format("unknown flavour {}, expected {}", msg_in.flavor, THREAD_STATE64).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
s_exception_handler_mutex.lock();
|
||||
thread_state64_t* state = (thread_state64_t*)msg_in.old_state;
|
||||
|
||||
HandlerResult result = HandlerResult::ExecuteNextHandler;
|
||||
if (!s_in_exception_handler)
|
||||
{
|
||||
s_in_exception_handler = true;
|
||||
|
||||
#ifdef _M_ARM64
|
||||
result = HandlePageFault(reinterpret_cast<void*>(state->__pc), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
|
||||
#else
|
||||
result = HandlePageFault(reinterpret_cast<void*>(state->__rip), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
|
||||
#endif
|
||||
s_in_exception_handler = false;
|
||||
}
|
||||
|
||||
// Set up the reply.
|
||||
msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0);
|
||||
msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port;
|
||||
msg_out.Head.msgh_local_port = MACH_PORT_NULL;
|
||||
msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100;
|
||||
msg_out.NDR = msg_in.NDR;
|
||||
|
||||
if (result != HandlerResult::ContinueExecution) // cooked
|
||||
{
|
||||
msg_out.RetCode = KERN_FAILURE;
|
||||
msg_out.flavor = 0;
|
||||
msg_out.new_stateCnt = 0;
|
||||
|
||||
// The crash handler on macOS or Linux doesn't use context passed to it
|
||||
// Stubbing it here is fine
|
||||
CrashHandler::CrashSignalHandler(-1, nullptr, nullptr);
|
||||
|
||||
pxFailRel("CrashSignalHandler returned when it should have terminated us!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV)
|
||||
msg_out.RetCode = KERN_SUCCESS;
|
||||
msg_out.flavor = THREAD_STATE64;
|
||||
msg_out.new_stateCnt = THREAD_STATE64_COUNT;
|
||||
memcpy(msg_out.new_state, msg_in.old_state, THREAD_STATE64_COUNT * sizeof(natural_t));
|
||||
}
|
||||
|
||||
msg_out.Head.msgh_size =
|
||||
offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t);
|
||||
send_size = msg_out.Head.msgh_size;
|
||||
option |= MACH_SEND_MSG;
|
||||
|
||||
s_exception_handler_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool PageFaultHandler::Install(Error* error)
|
||||
{
|
||||
exception_mask_t masks[EXC_TYPES_COUNT];
|
||||
mach_port_t ports[EXC_TYPES_COUNT];
|
||||
exception_behavior_t behaviors[EXC_TYPES_COUNT];
|
||||
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
|
||||
mach_msg_type_number_t count = EXC_TYPES_COUNT;
|
||||
|
||||
kern_return_t r = task_get_exception_ports(mach_task_self(), EXC_MASK_ALL,
|
||||
masks, &count, ports, behaviors, flavors);
|
||||
|
||||
mach_port_t port;
|
||||
if ((r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
|
||||
{
|
||||
pxFailRel(fmt::format("mach_port_allocate: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::thread sig_thread(PageFaultHandler::SignalHandler, port);
|
||||
sig_thread.detach();
|
||||
|
||||
if ((r = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_insert_right: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
|
||||
|
||||
if ((r = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE64)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("thread_set_exception_ports: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((r = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_port_t previous;
|
||||
if ((r = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)))
|
||||
{
|
||||
mach_port_deallocate(mach_task_self(), port);
|
||||
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
s_installed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx)
|
||||
{
|
||||
#if defined(_M_X86)
|
||||
@@ -839,4 +644,3 @@ bool PageFaultHandler::Install(Error* error)
|
||||
s_installed = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -202,7 +202,11 @@ void ControllerBindingWidget::onAutomaticBindingClicked()
|
||||
for (const QPair<QString, QString>& dev : m_dialog->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second));
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
action->setData(dev.first);
|
||||
connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
|
||||
added = true;
|
||||
@@ -1152,7 +1156,11 @@ void USBDeviceWidget::onAutomaticBindingClicked()
|
||||
for (const QPair<QString, QString>& dev : m_dialog->getDeviceList())
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action = menu.addAction(QStringLiteral("%1 (%2)").arg(dev.first).arg(dev.second));
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
action->setData(dev.first);
|
||||
connect(action, &QAction::triggered, this, [this, action]() { doDeviceAutomaticBinding(action->data().toString()); });
|
||||
added = true;
|
||||
|
||||
@@ -88,7 +88,11 @@ ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;
|
||||
void ControllerGlobalSettingsWidget::addDeviceToList(const QString& identifier, const QString& name)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
if(identifier.compare(name,Qt::CaseInsensitive) == 0)
|
||||
item->setText(identifier);
|
||||
else
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
|
||||
item->setData(Qt::UserRole, identifier);
|
||||
m_ui.deviceList->addItem(item);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,9 +10,7 @@
|
||||
|
||||
std::vector<BreakPoint> CBreakPoints::breakPoints_;
|
||||
u32 CBreakPoints::breakSkipFirstAtEE_ = 0;
|
||||
u64 CBreakPoints::breakSkipFirstTicksEE_ = 0;
|
||||
u32 CBreakPoints::breakSkipFirstAtIop_ = 0;
|
||||
u64 CBreakPoints::breakSkipFirstTicksIop_ = 0;
|
||||
std::vector<MemCheck> CBreakPoints::memChecks_;
|
||||
std::vector<MemCheck*> CBreakPoints::cleanupMemChecks_;
|
||||
bool CBreakPoints::breakpointTriggered_ = false;
|
||||
@@ -393,20 +391,18 @@ void CBreakPoints::SetSkipFirst(BreakPointCpu cpu, u32 pc)
|
||||
if (cpu == BREAKPOINT_EE)
|
||||
{
|
||||
breakSkipFirstAtEE_ = standardizeBreakpointAddress(pc);
|
||||
breakSkipFirstTicksEE_ = r5900Debug.getCycles();
|
||||
}
|
||||
else if (cpu == BREAKPOINT_IOP)
|
||||
{
|
||||
breakSkipFirstAtIop_ = pc;
|
||||
breakSkipFirstTicksIop_ = r3000Debug.getCycles();
|
||||
}
|
||||
}
|
||||
|
||||
u32 CBreakPoints::CheckSkipFirst(BreakPointCpu cpu, u32 cmpPc)
|
||||
{
|
||||
if (cpu == BREAKPOINT_EE && breakSkipFirstTicksEE_ == r5900Debug.getCycles())
|
||||
if (cpu == BREAKPOINT_EE && breakSkipFirstAtEE_ == r5900Debug.getPC())
|
||||
return breakSkipFirstAtEE_;
|
||||
else if (cpu == BREAKPOINT_IOP && breakSkipFirstTicksIop_ == r3000Debug.getCycles())
|
||||
else if (cpu == BREAKPOINT_IOP && breakSkipFirstAtIop_ == r3000Debug.getPC())
|
||||
return breakSkipFirstAtIop_;
|
||||
return 0;
|
||||
}
|
||||
@@ -414,9 +410,7 @@ u32 CBreakPoints::CheckSkipFirst(BreakPointCpu cpu, u32 cmpPc)
|
||||
void CBreakPoints::ClearSkipFirst()
|
||||
{
|
||||
breakSkipFirstAtEE_ = 0;
|
||||
breakSkipFirstTicksEE_ = 0;
|
||||
breakSkipFirstAtIop_ = 0;
|
||||
breakSkipFirstTicksIop_ = 0;
|
||||
}
|
||||
|
||||
const std::vector<MemCheck> CBreakPoints::GetMemCheckRanges()
|
||||
|
||||
@@ -3458,8 +3458,11 @@ void FullscreenUI::StartAutomaticBinding(u32 port)
|
||||
names.reserve(devices.size());
|
||||
for (auto& [name, display_name] : devices)
|
||||
{
|
||||
if(!StringUtil::compareNoCase(name, display_name))
|
||||
options.emplace_back(fmt::format("{}: {}", name, display_name), false);
|
||||
else
|
||||
options.emplace_back(std::move(display_name), false);
|
||||
names.push_back(std::move(name));
|
||||
options.emplace_back(std::move(display_name), false);
|
||||
}
|
||||
OpenChoiceDialog(FSUI_CSTR("Select Device"), false, std::move(options),
|
||||
[port, names = std::move(names)](s32 index, const std::string& title, bool checked) {
|
||||
|
||||
Reference in New Issue
Block a user