Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 53 additions & 18 deletions src/custommem.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include "callback.h"
#include "x64trace.h"
#include "custommem.h"
#ifndef _WIN32
#include "signals.h"
#endif
#include "khash.h"
#include "threads.h"
#include "rbtree.h"
Expand Down Expand Up @@ -562,24 +565,57 @@ static uintptr_t defered_prot_p = 0;
static size_t defered_prot_sz = 0;
static uint32_t defered_prot_prot = 0;
static mem_flag_t defered_prot_flags = MEM_ALLOCATED;
static sigset_t critical_prot = {0};
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
#define LOCK_PROT() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
#define LOCK_PROT_READ() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
#define LOCK_PROT_FAST() mutex_lock(&mutex_prot)
#define UNLOCK_PROT() if(defered_prot_p) { \
uintptr_t p = defered_prot_p; size_t sz = defered_prot_sz; uint32_t prot = defered_prot_prot; mem_flag_t f = defered_prot_flags;\
defered_prot_p = 0; \
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
mutex_unlock(&mutex_prot); \
setProtection_generic(p, sz, prot, f); \
} else { \
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
mutex_unlock(&mutex_prot); \
}
#define UNLOCK_PROT_READ() mutex_unlock(&mutex_prot); pthread_sigmask(SIG_SETMASK, &old_sig, NULL)
#define UNLOCK_PROT_FAST() mutex_unlock(&mutex_prot)

#ifdef _WIN32
void enter_critical_section(void) {}
void leave_critical_section(void) {}
#endif

static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
#define LOCK_PROT() \
do { \
enter_critical_section(); \
mutex_lock(&mutex_prot); \
} while (0)

#define LOCK_PROT_READ() \
do { \
enter_critical_section(); \
mutex_lock(&mutex_prot); \
} while (0)

#define LOCK_PROT_FAST() \
do { \
mutex_lock(&mutex_prot); \
} while (0)

#define UNLOCK_PROT() \
do { \
if (defered_prot_p) { \
uintptr_t p = defered_prot_p; \
size_t sz = defered_prot_sz; \
uint32_t prot = defered_prot_prot; \
mem_flag_t f = defered_prot_flags; \
defered_prot_p = 0; \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
setProtection_generic(p, sz, prot, f); \
} else { \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
} \
} while (0)

#define UNLOCK_PROT_READ() \
do { \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
} while (0)

#define UNLOCK_PROT_FAST() \
do { \
mutex_unlock(&mutex_prot); \
} while (0)

#ifdef TRACE_MEMSTAT
static uint64_t customMalloc_allocated = 0;
Expand Down Expand Up @@ -3095,7 +3131,6 @@ void init_custommem_helper(box64context_t* ctx)
for(int i=0; i<n_blocks; ++i)
rb_set(blockstree, (uintptr_t)p_blocks[i].block, (uintptr_t)p_blocks[i].block+p_blocks[i].size, i);
memprot = rbtree_init("memprot");
sigfillset(&critical_prot);
#ifdef DYNAREC
if(BOX64ENV(dynarec)) {
#ifdef JMPTABL_SHIFT4
Expand Down
14 changes: 14 additions & 0 deletions src/emu/x64emu.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ static uint32_t x86emu_parity_tab[8] =
0x69969669,
};

static void reset_deferred_signal(x64emu_t* emu)
{
#ifndef _WIN32
emu->critical_section = 0;
emu->deferred_signal_processing = 0;
emu->deferred_signal_count = 0;
memset((void*)emu->deferred_signal_pending, 0, sizeof(emu->deferred_signal_pending));
memset(emu->deferred_siginfo, 0, sizeof(emu->deferred_siginfo));
#endif
}

static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
{
emu->context = context;
Expand Down Expand Up @@ -90,6 +101,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
emu->mxcsr.x32 = 0x1f80;
// want some new jmpbuf for error recovery
emu->flags.need_jmpbuf = 1;
reset_deferred_signal(emu);
}

EXPORTDYN
Expand Down Expand Up @@ -219,6 +231,7 @@ void CloneEmu(x64emu_t *newemu, const x64emu_t* emu)
newemu->quit = emu->quit;
newemu->error = emu->error;
newemu->x64emu_parity_tab = emu->x64emu_parity_tab;
reset_deferred_signal(newemu);
}

void CopyEmu(x64emu_t *newemu, const x64emu_t* emu)
Expand Down Expand Up @@ -247,6 +260,7 @@ void CopyEmu(x64emu_t *newemu, const x64emu_t* emu)
newemu->mxcsr = emu->mxcsr;
newemu->quit = emu->quit;
newemu->error = emu->error;
reset_deferred_signal(newemu);
}

box64context_t* GetEmuContext(x64emu_t* emu)
Expand Down
8 changes: 8 additions & 0 deletions src/emu/x64emu_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "regs.h"
#include "os.h"
#include "box64context.h"
#include <signal.h>

typedef struct x64_ucontext_s x64_ucontext_t;
#ifdef BOX32
Expand Down Expand Up @@ -135,6 +136,13 @@ typedef struct x64emu_s {
tlsdatasize_t *tlsdata;
// other informations
int type; // EMUTYPE_xxx define
#ifndef _WIN32
volatile sig_atomic_t critical_section;
volatile sig_atomic_t deferred_signal_processing;
volatile sig_atomic_t deferred_signal_count;
volatile sig_atomic_t deferred_signal_pending[MAX_SIGNAL+1];
siginfo_t deferred_siginfo[MAX_SIGNAL+1];
#endif
#ifdef BOX32
int libc_err; // copy of errno from libc
int libc_herr; // copy of h_errno from libc
Expand Down
1 change: 1 addition & 0 deletions src/include/box64context.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ int AddTLSPartition(box64context_t* context, int tlssize);
// defined in fact in threads.c
void thread_set_emu(x64emu_t* emu);
void thread_forget_emu();
x64emu_t* thread_get_emu_no_create(void);
x64emu_t* thread_get_emu(void);

// relock the muxtex that were unlocked
Expand Down
5 changes: 5 additions & 0 deletions src/include/signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ int my___sigaction(x64emu_t* emu, int signum, const x64_sigaction_t *act, x64_si

int my_syscall_rt_sigaction(x64emu_t* emu, int signum, const x64_sigaction_restorer_t *act, x64_sigaction_restorer_t *oldact, int sigsetsize);

void enter_critical_section();
void leave_critical_section();
int defer_signal(x64emu_t* emu, int signum, siginfo_t* info);
void cancel_deferred_signal_processing(x64emu_t* emu);

void init_signal_helper(box64context_t* context);
void fini_signal_helper(void);

Expand Down
7 changes: 6 additions & 1 deletion src/libtools/signal32.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,7 @@ int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigin
#ifdef DYNAREC
dynablock_leave_runtime((dynablock_t*)cur_db);
#endif
cancel_deferred_signal_processing(emu);
#ifdef ANDROID
siglongjmp(*emu->jmpbuf, skip);
#else
Expand Down Expand Up @@ -817,6 +818,10 @@ int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, sigin

void my32_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
{
sig = signal_to_x64(sig);
x64emu_t* emu = thread_get_emu_no_create();
if (defer_signal(emu, sig, info))
return;
#ifdef DYNAREC
ucontext_t *p = (ucontext_t *)ucntx;
#ifdef ARM64
Expand All @@ -835,7 +840,7 @@ void my32_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
void* db = NULL;
#endif

my_sigactionhandler_oldcode_32(NULL, sig, 0, info, ucntx, NULL, db);
my_sigactionhandler_oldcode_32(emu, sig, 0, info, ucntx, NULL, db);
}


Expand Down
79 changes: 78 additions & 1 deletion src/libtools/signals.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,80 @@ x64emu_t* getEmuSignal(x64emu_t* emu, ucontext_t* p, dynablock_t* db)
}
#endif

void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void* ucntx, int* old_code, void* cur_db, uintptr_t x64pc);
#ifdef BOX32
int my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db);
#endif

static int is_signal_deferrable(int sig)
{
switch (sig) {
case X64_SIGSEGV:
case X64_SIGBUS:
case X64_SIGILL:
case X64_SIGABRT:
return 0;
}
return 1;
}

int defer_signal(x64emu_t* emu, int signum, siginfo_t* info)
{
if (!emu || signum < 0 || signum > MAX_SIGNAL || !is_signal_deferrable(signum) || emu->critical_section <= 0)
return 0;

if (info)
emu->deferred_siginfo[signum] = *info;
else
memset(&emu->deferred_siginfo[signum], 0, sizeof(emu->deferred_siginfo[signum]));
emu->deferred_siginfo[signum].si_signo = signum;
if (!emu->deferred_signal_pending[signum])
++emu->deferred_signal_count;
emu->deferred_signal_pending[signum] = 1;
return 1;
}

void cancel_deferred_signal_processing(x64emu_t* emu)
{
if (!emu) return;
emu->critical_section = 0;
emu->deferred_signal_processing = 0;
}

void enter_critical_section()
{
x64emu_t* emu = thread_get_emu_no_create();
if (emu) ++emu->critical_section;
}

void leave_critical_section()
{
x64emu_t* emu = thread_get_emu_no_create();
if (!emu || emu->critical_section <= 0)
return;
if (--emu->critical_section || !emu->deferred_signal_count || emu->deferred_signal_processing)
return;

emu->deferred_signal_processing = 1;
while (emu->deferred_signal_count) {
int handled = 0;
for (int sig = 1; sig <= MAX_SIGNAL; ++sig) {
if (!emu->deferred_signal_pending[sig])
continue;
siginfo_t info = emu->deferred_siginfo[sig];
emu->deferred_signal_pending[sig] = 0;
--emu->deferred_signal_count;
handled = 1;
my_sigactionhandler_oldcode(emu, sig, 0, &info, NULL, NULL, NULL, R_RIP);
}
if (!handled) {
emu->deferred_signal_count = 0;
break;
}
}
emu->deferred_signal_processing = 0;
}

int my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
{
int Locks = unlockMutex();
Expand Down Expand Up @@ -520,6 +591,7 @@ int my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigin
#ifdef DYNAREC
dynablock_leave_runtime((dynablock_t*)cur_db);
#endif
cancel_deferred_signal_processing(emu);
#ifdef ANDROID
siglongjmp(*emu->jmpbuf, skip);
#else
Expand Down Expand Up @@ -841,6 +913,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
#if defined(RV64) || defined(PPC64LE)
emu->xSPSave = emu->old_savedsp;
#endif
cancel_deferred_signal_processing(emu);
#ifdef ANDROID
siglongjmp(*(JUMPBUFF*)emu->jmpbuf, 3);
#else
Expand Down Expand Up @@ -915,6 +988,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
#if defined(RV64) || defined(PPC64LE)
emu->xSPSave = emu->old_savedsp;
#endif
cancel_deferred_signal_processing(emu);
#ifdef ANDROID
siglongjmp(*(JUMPBUFF*)emu->jmpbuf, 2);
#else
Expand Down Expand Up @@ -1259,13 +1333,16 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "%04d|Repeated SIGSEGV with Access error on %
void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
{
sig = signal_to_x64(sig);
x64emu_t* emu = thread_get_emu_no_create();
if (defer_signal(emu, sig, info))
return;
void* pc = NULL;
#ifdef DYNAREC
ucontext_t *p = (ucontext_t *)ucntx;
pc = (void*)CONTEXT_PC(p);
#endif
dynablock_t* db = FindDynablockFromNativeAddress(pc);
x64emu_t* emu = thread_get_emu();
if (!emu) emu = thread_get_emu();
uintptr_t x64pc = R_RIP;
if(db)
x64pc = getX64Address(db, (uintptr_t)pc);
Expand Down
8 changes: 7 additions & 1 deletion src/libtools/threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,13 @@ void thread_set_emu(x64emu_t* emu)
pthread_setspecific(thread_key, et);
}

x64emu_t* thread_get_emu()
x64emu_t* thread_get_emu_no_create(void)
{
emuthread_t* et = (emuthread_t*)pthread_getspecific(thread_key);
return et ? et->emu : NULL;
}

x64emu_t* thread_get_emu(void)
{
emuthread_t *et = (emuthread_t*)pthread_getspecific(thread_key);
if(!et) {
Expand Down
Loading