mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
Exception handling fix
This commit is contained in:
parent
6627cc9666
commit
6545df2b15
@ -192,32 +192,48 @@ void decode_x64_reg_op(const u8* code, x64_op_t& decoded_op, x64_reg_t& decoded_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
typedef CONTEXT x64_context;
|
||||
|
||||
#define RIP 16
|
||||
#define X64REG(context, reg) ((&context->Rax)[reg])
|
||||
|
||||
#else
|
||||
|
||||
typedef ucontext_t x64_context;
|
||||
typedef decltype(REG_RIP) reg_table_t;
|
||||
#define RIP 16
|
||||
|
||||
static const reg_table_t reg_table[17] =
|
||||
{
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
if (u == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull)
|
||||
REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,
|
||||
REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_RIP
|
||||
};
|
||||
|
||||
#define X64REG(context, reg) (context->uc_mcontext.gregs[reg_table[reg]])
|
||||
|
||||
#endif
|
||||
|
||||
bool handle_access_violation(const u32 addr, x64_context* context)
|
||||
{
|
||||
const u32 addr = (u32)addr64;
|
||||
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers
|
||||
{
|
||||
// one x64 instruction is manually decoded and interpreted
|
||||
x64_op_t op;
|
||||
x64_reg_t reg;
|
||||
size_t size;
|
||||
decode_x64_reg_op((const u8*)pExp->ContextRecord->Rip, op, reg, size);
|
||||
decode_x64_reg_op((const u8*)X64REG(context, RIP), op, reg, size);
|
||||
|
||||
// get x64 reg value (for store operations)
|
||||
u64 reg_value;
|
||||
if (reg - X64R32 < 16)
|
||||
{
|
||||
// load the value from x64 register
|
||||
reg_value = (u32)(&pExp->ContextRecord->Rax)[reg - X64R32];
|
||||
reg_value = (u32)X64REG(context, reg - X64R32);
|
||||
}
|
||||
else if (reg == X64_IMM32)
|
||||
{
|
||||
// load the immediate value (assuming it's at the end of the instruction)
|
||||
reg_value = *(u32*)(pExp->ContextRecord->Rip + size - 4);
|
||||
reg_value = *(u32*)(X64REG(context, RIP) + size - 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -230,14 +246,12 @@ void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
{
|
||||
case X64OP_LOAD:
|
||||
{
|
||||
assert(!is_writing);
|
||||
reg_value = re32(Memory.ReadMMIO32(addr));
|
||||
save_reg = true;
|
||||
break;
|
||||
}
|
||||
case X64OP_STORE:
|
||||
{
|
||||
assert(is_writing);
|
||||
Memory.WriteMMIO32(addr, re32((u32)reg_value));
|
||||
break;
|
||||
}
|
||||
@ -250,7 +264,7 @@ void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
if (reg - X64R32 < 16)
|
||||
{
|
||||
// store the value into x64 register
|
||||
(&pExp->ContextRecord->Rax)[reg - X64R32] = (u32)reg_value;
|
||||
X64REG(context, reg - X64R32) = (u32)reg_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -259,14 +273,31 @@ void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
}
|
||||
|
||||
// skip decoded instruction
|
||||
pExp->ContextRecord->Rip += size;
|
||||
X64REG(context, RIP) += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
{
|
||||
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64)
|
||||
{
|
||||
if (handle_access_violation((u32)addr64, pExp->ContextRecord))
|
||||
{
|
||||
// restore context (further code shouldn't be reached)
|
||||
RtlRestoreContext(pExp->ContextRecord, nullptr);
|
||||
|
||||
// it's dangerous because destructors won't be executed
|
||||
}
|
||||
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory
|
||||
throw fmt::Format("Access violation %s location 0x%x", is_writing ? "writing" : "reading", addr);
|
||||
|
||||
throw fmt::Format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64);
|
||||
}
|
||||
|
||||
// else some fatal error (should crash)
|
||||
@ -283,79 +314,15 @@ static const reg_table_t reg_table[16] =
|
||||
|
||||
void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
{
|
||||
ucontext_t* const ctx = (ucontext_t*)uct;
|
||||
const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr();
|
||||
//const bool is_writing = false; // TODO: get it correctly
|
||||
if (addr64 < 0x100000000ull && GetCurrentNamedThread())
|
||||
if ((u32)addr64 == addr64 && GetCurrentNamedThread())
|
||||
{
|
||||
const u32 addr = (u32)addr64;
|
||||
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers
|
||||
if (handle_access_violation((u32)addr64, (ucontext_t*)uct))
|
||||
{
|
||||
// one x64 instruction is manually decoded and interpreted
|
||||
x64_op_t op;
|
||||
x64_reg_t reg;
|
||||
size_t size;
|
||||
decode_x64_reg_op((const u8*)ctx->uc_mcontext.gregs[REG_RIP], op, reg, size);
|
||||
|
||||
// get x64 reg value (for store operations)
|
||||
u64 reg_value;
|
||||
if (reg - X64R32 < 16)
|
||||
{
|
||||
// load the value from x64 register
|
||||
reg_value = (u32)ctx->uc_mcontext.gregs[reg_table[reg - X64R32]];
|
||||
}
|
||||
else if (reg == X64_IMM32)
|
||||
{
|
||||
// load the immediate value (assuming it's at the end of the instruction)
|
||||
reg_value = *(u32*)(ctx->uc_mcontext.gregs[REG_RIP] + size - 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!"Invalid x64_reg_t value");
|
||||
return; // proceed execution
|
||||
}
|
||||
|
||||
bool save_reg = false;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case X64OP_LOAD:
|
||||
{
|
||||
//assert(!is_writing);
|
||||
reg_value = re32(Memory.ReadMMIO32(addr));
|
||||
save_reg = true;
|
||||
break;
|
||||
}
|
||||
case X64OP_STORE:
|
||||
{
|
||||
//assert(is_writing);
|
||||
Memory.WriteMMIO32(addr, re32((u32)reg_value));
|
||||
break;
|
||||
}
|
||||
default: assert(!"Invalid x64_op_t value");
|
||||
}
|
||||
|
||||
// save x64 reg value (for load operations)
|
||||
if (save_reg)
|
||||
{
|
||||
if (reg - X64R32 < 16)
|
||||
{
|
||||
// store the value into x64 register
|
||||
ctx->uc_mcontext.gregs[reg_table[reg - X64R32]] = (u32)reg_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!"Invalid x64_reg_t value (saving)");
|
||||
}
|
||||
}
|
||||
|
||||
// skip decoded instruction
|
||||
ctx->uc_mcontext.gregs[REG_RIP] += size;
|
||||
|
||||
return; // now execution should proceed
|
||||
//setcontext(ctx);
|
||||
}
|
||||
|
||||
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory
|
||||
// TODO: this may be wrong
|
||||
throw fmt::Format("Access violation %s location 0x%x", /*is_writing ? "writing" : "reading"*/ "at", addr);
|
||||
}
|
||||
|
||||
|
@ -1067,5 +1067,5 @@ void cellAudio_init(Module *pxThis)
|
||||
|
||||
void cellAudio_load()
|
||||
{
|
||||
// never called :(
|
||||
// CELL_SYSMODULE AUDIO module is rarely loaded manually, so cellAudio_load() won't be called in every case
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user