Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1683 from reicast/skmp/page-fault-mashaling
Browse files Browse the repository at this point in the history
linux/signals: Double pagefault for marshaling segfaults
  • Loading branch information
skmp authored Jul 15, 2019
2 parents 9296f82 + 45955b6 commit 1c7b5e6
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 16 deletions.
11 changes: 11 additions & 0 deletions libswirl/libswirl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "input/gamepad_device.h"
#include "rend/TexCache.h"

#define fault_printf(...)

void FlushCache();
void LoadCustom();

Expand Down Expand Up @@ -943,28 +945,37 @@ void dc_loadstate()

bool dc_handle_fault(unat addr, rei_host_context_t* ctx)
{
fault_printf("dc_handle_fault: %p from %p\n", (u8*)addr, (u8*)ctx->pc);

bool dyna_cde = ((unat)CC_RX2RW(ctx->pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx->pc) < (unat)(CodeCache + CODE_SIZE));

u8* address = (u8*)addr;

if (VramLockedWrite(address))
{
fault_printf("VramLockedWrite!\n");

return true;
}
else if (_vmem_bm_LockedWrite(address))
{
fault_printf("dc_handle_fault: _vmem_bm_LockedWrite!\n");

return true;
}
else if (bm_LockedWrite(address))
{
fault_printf("dc_handle_fault: bm_LockedWrite!\n");
return true;
}
else if (dyna_cde && rdv_ngen && rdv_ngen->Rewrite(ctx))
{
fault_printf("dc_handle_fault: rdv_ngen->Rewrite!\n");
return true;
}
else
{
fault_printf("dc_handle_fault: not handled!\n");
return false;
}
}
88 changes: 81 additions & 7 deletions libswirl/linux/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

#include "libswirl.h"

#define fault_printf(...)

#if !defined(TARGET_NO_EXCEPTIONS)

#if HOST_OS == OS_DARWIN
Expand All @@ -53,28 +55,100 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
}
#endif

void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
u8* trap_ptr_fault;
static thread_local unat trap_si_addr;
static thread_local unat trap_pc;

extern "C" u8* generic_fault_handler ()
{
fault_printf("generic_fault_handler\n");
rei_host_context_t ctx;

context_from_segfault(&ctx, segfault_ctx);
fault_printf("generic_fault_handler\n");
context_from_segfault(&ctx);

fault_printf("generic_fault_handler: original ptr: %p, trap ptr: %p\n", ctx.pc, trap_pc);
ctx.pc = trap_pc;

unat addr = (unat)si->si_addr;
fault_printf("generic_fault_handler\n");

if (dc_handle_fault(addr, &ctx))
if (dc_handle_fault(trap_si_addr, &ctx))
{
context_to_segfault(&ctx, segfault_ctx);
fault_printf("generic_fault_handler: final ptr: %p, trap ptr: %p\n", ctx.pc, trap_pc);
context_to_segfault(&ctx);
fault_printf("generic_fault_handler2\n");
}
else
{
printf("SIGSEGV @ %lx -> %p was not in handled\n", ctx.pc, si->si_addr);
printf("Restoring default SIGSEGV handler\n");
fault_printf("SIGSEGV @ %lx -> %p was not in handled\n", ctx.pc, (void*)trap_si_addr);
fault_printf("Restoring default SIGSEGV handler\n");
signal(SIGSEGV, SIG_DFL);
}

fault_printf("generic_fault_handler end\n");
return trap_ptr_fault;
}



void re_raise_fault()
{
__asm__ __volatile__(
#if HOST_CPU == CPU_X86
"sub $8192, %esp\n"
"and $-32, %esp\n"
"call generic_fault_handler\n"
"movb $0, (%eax)"
#elif HOST_CPU == CPU_X64
"subq $8192, %rsp\n"
"andq $-32, %rsp\n"
"call generic_fault_handler\n"
"movb $0, (%rax)"
#elif HOST_CPU == CPU_ARM
"sub sp, 8192\n"
"and sp, -32\n"
"bl generic_fault_handler\n"
"ldr r1, [r0]"
#elif HOST_CPU == CPU_ARM64
"sub x0, sp, #8192\n"
"and sp, x0, #-32\n"
"bl generic_fault_handler\n"
"ldr w1, [x0]"
#else
#error missing cpu
#endif
);
}

void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
{
fault_printf("fault_handler %p %p\n", si->si_addr, trap_ptr_fault);

if ((unat)si->si_addr == (unat)trap_ptr_fault)
{
segfault_load(segfault_ctx);
rei_host_context_t ctx;
context_from_segfault(&ctx);

fault_printf("fault_handler:resume %p\n", ctx.pc);
}
else
{
fault_printf("fault_handler:catch -> thunking to %p\n", trap_pc);
trap_si_addr = (unat)si->si_addr;
segfault_store(segfault_ctx);
segfault_set_pc(segfault_ctx, (unat)&re_raise_fault, &trap_pc);
}

fault_printf("fault_handler exit\n");
}

void install_fault_handler(void)
{
trap_ptr_fault = (u8*)mmap(0, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);

fault_printf("trap_ptr_fault %p\n", trap_ptr_fault);

struct sigaction act, segv_oact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = fault_handler;
Expand Down
72 changes: 66 additions & 6 deletions libswirl/linux/context.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "context.h"

#define fault_printf(...)

#if defined(_ANDROID)
#include <asm/sigcontext.h>
#else
Expand All @@ -16,7 +18,16 @@

//////

#define MCTX(p) (((ucontext_t *)(segfault_ctx))->uc_mcontext p)
#define UCTX(p) (((ucontext_t *)(segfault_ctx))->uc_mcontext p)

#if HOST_OS == OS_DARWIN
#define UCTX_type mcontext_t
#define UCTX_data (UCTX())
#else
#define UCTX_type mcontext_t
#define UCTX_data (&UCTX())
#endif

template <typename Ta, typename Tb>
void bicopy(Ta& rei, Tb& seg, bool to_segfault) {
if (to_segfault) {
Expand All @@ -26,8 +37,29 @@ void bicopy(Ta& rei, Tb& seg, bool to_segfault) {
rei = seg;
}
}
#if !defined(TARGET_NO_EXCEPTIONS)
static thread_local UCTX_type segfault_copy;
#endif

void segfault_store(void* segfault_ctx) {
#if !defined(TARGET_NO_EXCEPTIONS)
memcpy(&segfault_copy, UCTX_data, sizeof(segfault_copy));

void context_segfault(rei_host_context_t* reictx, void* segfault_ctx, bool to_segfault) {
fault_printf("sgctx stored, %d pc: %p\n", sizeof(segfault_copy), segfault_copy.gregs[REG_RIP]);
#endif
}

void segfault_load(void* segfault_ctx) {
#if !defined(TARGET_NO_EXCEPTIONS)
memcpy(UCTX_data, &segfault_copy, sizeof(*UCTX_data));

fault_printf("sgctx loaded, %d pc: %p\n", sizeof(*UCTX_data), UCTX_data->gregs[REG_RIP]);
#endif
}

#define MCTX(p) ((*(UCTX_type*)segfault_ctx) p)

void context_segfault_bicopy(rei_host_context_t* reictx, void* segfault_ctx, bool to_segfault) {

#if !defined(TARGET_NO_EXCEPTIONS)
#if HOST_CPU == CPU_ARM
Expand Down Expand Up @@ -78,7 +110,9 @@ void context_segfault(rei_host_context_t* reictx, void* segfault_ctx, bool to_se
#elif defined(__NetBSD__)
bicopy(reictx->pc, MCTX(.__gregs[_REG_RIP]), to_segfault);
#elif HOST_OS == OS_LINUX
fault_printf("pc set: %d, value: %p %p\n", to_segfault, reictx->pc, MCTX(.gregs[REG_RIP]));
bicopy(reictx->pc, MCTX(.gregs[REG_RIP]), to_segfault);
fault_printf("pc set: %d, value: %p %p\n", to_segfault, reictx->pc, MCTX(.gregs[REG_RIP]));
#elif HOST_OS == OS_DARWIN
bicopy(reictx->pc, MCTX(->__ss.__rip), to_segfault);
#else
Expand All @@ -95,10 +129,36 @@ void context_segfault(rei_host_context_t* reictx, void* segfault_ctx, bool to_se

}

void context_from_segfault(rei_host_context_t* reictx, void* segfault_ctx) {
context_segfault(reictx, segfault_ctx, false);

void segfault_set_pc(void* segfault_ctx, unat new_pc, unat* old_pc)
{
#if !defined(TARGET_NO_EXCEPTIONS)
rei_host_context_t ctx;

context_segfault_bicopy(&ctx, UCTX_data, false);
fault_printf("segfault_set_pc: old pc: %lx\n", ctx.pc);

*old_pc = ctx.pc;
ctx.pc = new_pc;

context_segfault_bicopy(&ctx, UCTX_data, true);
fault_printf("segfault_set_pc: new pc: %lx\n", ctx.pc);
#endif
}

void context_to_segfault(rei_host_context_t* reictx, void* segfault_ctx) {
context_segfault(reictx, segfault_ctx, true);

void context_from_segfault(rei_host_context_t* reictx) {
#if !defined(TARGET_NO_EXCEPTIONS)
fault_printf("context from segfault pc: %p, %p\n",reictx->pc, segfault_copy.gregs[REG_RIP]);
context_segfault_bicopy(reictx, &segfault_copy, false);
fault_printf("context from segfault pc: %p, %p\n",reictx->pc, segfault_copy.gregs[REG_RIP]);
#endif
}

void context_to_segfault(rei_host_context_t* reictx) {
#if !defined(TARGET_NO_EXCEPTIONS)
fault_printf("context to segfault pc: %p, %p\n",reictx->pc, segfault_copy.gregs[REG_RIP]);
context_segfault_bicopy(reictx, &segfault_copy, true);
fault_printf("context to segfault pc: %p, %p\n",reictx->pc, segfault_copy.gregs[REG_RIP]);
#endif
}
9 changes: 7 additions & 2 deletions libswirl/linux/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@

#include "oslib/context.h"

void context_from_segfault(rei_host_context_t* reictx, void* segfault_ctx);
void context_to_segfault(rei_host_context_t* reictx, void* segfault_ctx);
void segfault_store(void* segfault_ctx);
void segfault_load(void* segfault_ctx);
void segfault_set_pc(void* segfault_ctx, unat new_pc, unat* old_pc);

void context_from_segfault(rei_host_context_t* reictx);
void context_to_segfault(rei_host_context_t* reictx);

3 changes: 2 additions & 1 deletion libswirl/linux/nixprof/nixprof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ void sample_Syms(u8* data,u32 len)
void prof_handler (int sn, siginfo_t * si, void *ctxr)
{
rei_host_context_t ctx;
context_from_segfault(&ctx, ctxr);
segfault_store(ctxr);
context_from_segfault(&ctx);

int thd=-1;
if (pthread_self()==thread[0]) thd=0;
Expand Down

0 comments on commit 1c7b5e6

Please sign in to comment.