Skip to content

Commit

Permalink
[ARM64_DYNAREC] Improved signal handling and flags handling (tbd on o…
Browse files Browse the repository at this point in the history
…ther archs)
  • Loading branch information
ptitSeb committed Dec 31, 2024
1 parent ca8d569 commit 1d20968
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 50 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ if(ARM_DYNAREC)
${DYNAREC_SRC}

"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_arch.c"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_immenc.c"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
Expand Down
81 changes: 81 additions & 0 deletions src/dynarec/arm64/dynarec_arm64_arch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <stddef.h>
#include <stdio.h>
#include <ucontext.h>

#include "debug.h"
#include "dynablock.h"
#include "x64emu.h"
#include "emu/x64emu_private.h"
#include "x64run.h"
#include "emu/x64run_private.h"
#include "dynarec/dynablock_private.h"
#include "dynarec_arm64_arch.h"

size_t get_size_arch(dynarec_arm_t* dyn)
{
if(!box64_dynarec_nativeflags)
return 0;
return dyn->isize*sizeof(arch_flags_t);
}

void populate_arch(dynarec_arm_t* dyn, void* p)
{
if(!box64_dynarec_nativeflags)
return;

arch_flags_t* flags = p;
for(int i=0; i<dyn->size; ++i) {
flags[i].defered = dyn->insts[i].f_entry.dfnone==0;
flags[i].vf = dyn->insts[i].need_nat_flags&NF_VF;
flags[i].nf = dyn->insts[i].need_nat_flags&NF_SF;
flags[i].eq = dyn->insts[i].need_nat_flags&NF_EQ;
flags[i].cf = dyn->insts[i].need_nat_flags&NF_CF;
flags[i].inv_cf = !dyn->insts[i].normal_carry;
}
}

int getX64AddressInst(dynablock_t* db, uintptr_t native_addr); // define is signal.c

// NZCV N
#define NZCV_N 31
// NZCV Z
#define NZCV_Z 30
// NZCV C
#define NZCV_C 29
// NZCV V
#define NZCV_V 28

void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
{
if(!db->arch_size || !db->arch)
return;
arch_flags_t* flags = db->arch;
int ninst = getX64AddressInst(db, x64pc);
printf_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d, flags:%s %c%c%c%c%s\n", db, (void*)x64pc, ninst, flags[ninst-1].defered?"defered":"", flags[ninst-1].vf?'V':' ', flags[ninst-1].nf?'S':' ', flags[ninst-1].eq?'Z':' ', flags[ninst-1].cf?'C':' ', (flags[ninst-1].cf && flags[ninst-1].inv_cf)?"inverted":"");
if(ninst<0)
return;
if(ninst==0) {
CHECK_FLAGS(emu);
return;
}
if(flags[ninst-1].defered) {
CHECK_FLAGS(emu);
//return;
}
if(flags[ninst-1].nf) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
}
if(flags[ninst-1].vf) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_OF);
}
if(flags[ninst-1].eq) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_Z), F_ZF);
}
if(flags[ninst-1].cf) {
if(flags[ninst-1].inv_cf) {
CONDITIONAL_SET_FLAG((p->uc_mcontext.pstate&(1<<NZCV_C))==0, F_CF);
} else {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
}
}
}
28 changes: 28 additions & 0 deletions src/dynarec/arm64/dynarec_arm64_arch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef __DYNAREC_ARM_ARCH_H__
#define __DYNAREC_ARM_ARCH_H__

#include <stddef.h>
#include <ucontext.h>

#include "x64emu.h"
#include "box64context.h"
#include "dynarec.h"
#include "dynarec_arm64_private.h"

typedef struct arch_flags_s
{
uint8_t defered:1;
uint8_t nf:1;
uint8_t eq:1;
uint8_t vf:1;
uint8_t cf:1;
uint8_t inv_cf:1;
} arch_flags_t;

// get size of arch specific info (can be 0)
size_t get_size_arch(dynarec_arm_t* dyn);
//populate the array
void populate_arch(dynarec_arm_t* dyn, void* p);
//adjust flags and more
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t native_addr);
#endif // __DYNAREC_ARM_ARCH_H__
2 changes: 2 additions & 0 deletions src/dynarec/dynablock_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ typedef struct dynablock_s {
uint8_t is32bits:1;
int isize;
instsize_t* instsize;
void* arch; // arch dependant per inst info (can be NULL)
size_t arch_size; // size of of arch dependant infos
void* jmpnext; // a branch jmpnext code when block is marked
} dynablock_t;

Expand Down
12 changes: 12 additions & 0 deletions src/dynarec/dynarec_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
#include "arm64/arm64_printer.h"
#include "arm64/dynarec_arm64_private.h"
#include "arm64/dynarec_arm64_functions.h"
#include "arm64/dynarec_arm64_arch.h"
// Limit here is defined by LD litteral, that is 19bits
#define MAXBLOCK_SIZE ((1<<19)-200)

#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
#define UPDATE_SPECIFICS(A) updateNativeFlags(A)
#define PREUPDATE_SPECIFICS(A)

#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B) populate_arch(A, B)
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#elif defined(LA64)

#define instruction_native_t instruction_la64_t
Expand All @@ -45,6 +49,10 @@
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)

#define ARCH_SIZE(A) 0
#define ARCH_FILL(A, B) {}
#define ARCH_ADJUST(A, B, C, D) {}
#elif defined(RV64)

#define instruction_native_t instruction_rv64_t
Expand All @@ -68,6 +76,10 @@
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)

#define ARCH_SIZE(A) 0
#define ARCH_FILL(A, B) {}
#define ARCH_ADJUST(A, B, C, D) {}
#else
#error Unsupported platform
#endif
Expand Down
15 changes: 13 additions & 2 deletions src/dynarec/dynarec_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
B+16 .. B+23 : jmpnext (or jmp_epilog) address. jumpnext is used when the block needs testing
B+24 .. B+31 : empty (in case an architecture needs more than 2 opcodes)
B+32 .. B+32+sz : instsize (compressed array with each instruction length on x64 and native side)
C .. C+sz : arch: arch specific info (likes flags info) per inst (can be absent)
*/
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
Expand Down Expand Up @@ -725,14 +726,16 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
insts_rsize = (insts_rsize+7)&~7; // round the size...
size_t native_size = (helper.native_size+7)&~7; // round the size...
size_t arch_size = ARCH_SIZE(&helper);
// ok, now allocate mapped memory, with executable flag on
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
// dynablock_t* block (arm insts) table64 jmpnext code instsize
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch
void* actual_p = (void*)AllocDynarecMap(sz);
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
void* tablestart = p + native_size;
void* next = tablestart + helper.table64size*sizeof(uint64_t);
void* instsize = next + 4*sizeof(void*);
void* arch = instsize + insts_rsize;
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
CancelBlock64(0);
Expand Down Expand Up @@ -784,6 +787,14 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
block->always_test = helper.always_test;
block->dirty = block->always_test;
block->is32bits = is32bits;
if(arch_size) {
block->arch = arch;
block->arch_size = arch_size;
ARCH_FILL(&helper, arch);
} else {
block->arch = NULL;
block->arch_size = arch_size;
}
*(dynablock_t**)next = block;
*(void**)(next+3*sizeof(void*)) = native_next;
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
Expand Down
5 changes: 3 additions & 2 deletions src/libtools/signal32.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ void convert_siginfo_to_32(void* d, void* s, int sig)
int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits);
#define is_memprot_locked (1<<1)
#define is_dyndump_locked (1<<8)
void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
{
int Locks = unlockMutex();
int log_minimum = (box64_showsegv)?LOG_NONE:((sig==SIGSEGV && my_context->is_sigaction[sig])?LOG_DEBUG:LOG_INFO);
Expand All @@ -477,7 +477,8 @@ void my_sigactionhandler_oldcode_32(int32_t sig, int simple, siginfo_t* info, vo

uintptr_t restorer = my_context->restorer[sig];
// get that actual ESP first!
x64emu_t *emu = thread_get_emu();
if(!emu)
emu = thread_get_emu();
uintptr_t frame = R_RSP;
#if defined(DYNAREC)
#if defined(ARM64)
Expand Down
Loading

0 comments on commit 1d20968

Please sign in to comment.