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
4 changes: 4 additions & 0 deletions src/dynarec/dynarec_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
#define ARCH_HOST_CALL(A, B, C) 0
extern uint32_t arm64_crc(void* p, uint32_t len);
extern uint32_t arm64_x31_hash(void* p, uint32_t len);
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B); else return arm64_x31_hash(A, B)
Expand Down Expand Up @@ -74,6 +75,7 @@ extern void arm64_next_invalid();
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
#define ARCH_HOST_CALL(A, B, C) arch_host_call(A, B, C)
extern uint32_t la64_crc(void* p, uint32_t len);
extern void la64_crc_autocrc(); // same as la64_crc, but not using regular ABI
#define ARCH_CRC(A, B) return la64_crc(A, B)
Expand Down Expand Up @@ -117,6 +119,7 @@ extern void la64_next_invalid();
#define ARCH_ADJUST(A, B, C, D) {}
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
#define ARCH_HOST_CALL(A, B, C) 0

#define ARCH_NOP 0b0010011
#define ARCH_UDF 0xc0001073
Expand Down Expand Up @@ -153,6 +156,7 @@ extern void la64_next_invalid();
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
#define ARCH_HOST_CALL(A, B, C) 0
extern uint32_t ppc64le_fast_hash(void* p, uint32_t len);
#define ARCH_CRC(A, B) return ppc64le_fast_hash(A, B)

Expand Down
42 changes: 35 additions & 7 deletions src/dynarec/la64/dynarec_la64_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,37 @@

typedef struct arch_arch_s
{
uint16_t unaligned:1;
uint16_t seq:10; // how many instruction on the same values
uint16_t up32; // GPRs with pending 32-bit zero-up at this instruction
uint16_t ymm_zero; // YMM upper halves with a deferred architectural zero
int16_t rsp; // pending rsp offset at this instruction
uint16_t unaligned : 1;
uint16_t host_call : 1; // instruction performs a native call
uint16_t seq : 10; // how many instruction on the same values
uint16_t up32; // GPRs with pending 32-bit zero-up at this instruction
uint16_t ymm_zero; // YMM upper halves with a deferred architectural zero
int16_t rsp; // pending rsp offset at this instruction
uint32_t call_window; // spill offset within the instruction
} arch_arch_t;

typedef struct arch_build_s
{
uint8_t unaligned;
uint8_t host_call;
uint16_t up32;
uint16_t ymm_zero;
int16_t rsp;
uint32_t call_window;
} arch_build_t;

static int arch_build(dynarec_la64_t* dyn, int ninst, arch_build_t* arch)
{
memset(arch, 0, sizeof(arch_build_t));
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
arch->host_call = dyn->insts[ninst].host_call;
arch->call_window = dyn->insts[ninst].call_window;
// pending 32-bit zero-ups at this instruction
arch->up32 = dyn->insts[ninst].up32_pending;
arch->ymm_zero = dyn->insts[ninst].vector_liveness.ymm_pending;
arch->rsp = dyn->insts[ninst].rsp_entry;
return arch->unaligned || arch->up32 || arch->ymm_zero || arch->rsp;
return arch->unaligned || arch->host_call || arch->up32 || arch->ymm_zero || arch->rsp;
}

size_t get_size_arch(dynarec_la64_t* dyn)
Expand Down Expand Up @@ -73,6 +79,8 @@ size_t get_size_arch(dynarec_la64_t* dyn)
static void build_next(arch_arch_t* arch, arch_build_t* build)
{
arch->unaligned = build->unaligned;
arch->host_call = build->host_call;
arch->call_window = build->call_window;
arch->seq = 0;
arch->up32 = build->up32;
arch->ymm_zero = build->ymm_zero;
Expand Down Expand Up @@ -134,6 +142,26 @@ int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
return arch->unaligned;
}

int arch_host_call(dynablock_t* db, void* native_pc, uintptr_t x64pc)
{
if (!db) return 0;
if (!db->arch_size || !db->arch) return 0;
int ninst = getX64AddressInst(db, x64pc);
if (ninst < 0 || ninst >= db->isize) return 0;
arch_arch_t* arch = arch_for_ninst(db, ninst);
if (!arch->host_call || !arch->call_window) return 0;
// getX64Address
uintptr_t addr = (uintptr_t)db->block + db->prefixsize;
int i = 0;
for (int inst = 0; inst < ninst; ++inst) {
do {
addr += db->instsize[i].nat * 4;
++i;
} while ((db->instsize[i - 1].x64 == 15) || (db->instsize[i - 1].nat == 15));
}
return ((uintptr_t)native_pc - addr) >= arch->call_window;
}

void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
{
(void)p;
Expand All @@ -154,5 +182,5 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
ymm_zero &= ymm_zero - 1;
emu->ymm[r].u128 = 0;
}
if (arch->rsp) emu->regs[_SP].q[0] += arch->rsp;
if (arch->rsp && !arch->host_call) emu->regs[_SP].q[0] += arch->rsp;
}
2 changes: 2 additions & 0 deletions src/dynarec/la64/dynarec_la64_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ void* populate_arch(dynarec_la64_t* dyn, void* p, size_t sz);
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
// get if instruction can be regenerated for unaligned access
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
// get if the native pc is in the native call window of the instruction
int arch_host_call(dynablock_t* db, void* native_pc, uintptr_t x64pc);
#endif // __DYNAREC_LA_ARCH_H__
2 changes: 2 additions & 0 deletions src/dynarec/la64/dynarec_la64_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret,
STORE_REG(RSP);
STORE_REG(RBP);
ST_D(xRIP, xEmu, offsetof(x64emu_t, ip));
dyn->insts[ninst].call_window = dyn->native_size - dyn->insts[ninst].address;
}
TABLE64C(reg, fnc);
if (arg1) MV(A1, arg1);
Expand Down Expand Up @@ -641,6 +642,7 @@ void call_n(dynarec_la64_t* dyn, int ninst, void* fnc, int w)
ST_D(xRSP, xEmu, offsetof(x64emu_t, regs[_SP]));
ST_D(xRBP, xEmu, offsetof(x64emu_t, regs[_BP]));
ST_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
dyn->insts[ninst].call_window = dyn->native_size - dyn->insts[ninst].address;
int nfp = (abs(w) & 15) - 1;
if (nfp > 0)
for (int i = 0; i < nfp; ++i)
Expand Down
1 change: 1 addition & 0 deletions src/dynarec/la64/dynarec_la64_pass0.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
dyn->insts[ninst].comis_fusion = -1; \
dyn->insts[ninst].comis_mark = 0; \
dyn->insts[ninst].host_call = 0; \
dyn->insts[ninst].call_window = 0; \
dyn->insts[ninst].f_entry = dyn->f; \
if (ninst) { dyn->insts[ninst - 1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst - 1].x64.addr; } \
AREFLAGSNEEDED()
Expand Down
1 change: 1 addition & 0 deletions src/dynarec/la64/dynarec_la64_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ typedef struct instruction_la64_s {
int8_t comis_fusion;
uint8_t comis_mark:1;
uint8_t host_call:1;
int call_window; // native byte offset where the regs have been spilled to emu before a native call
int16_t rsp_entry; // pending rsp offset at entry
int16_t rsp_flush; // rsp offset to emit right after this push/pop
uint8_t rsp_merge : 1; // this push/pop is emitted with merged rsp offset
Expand Down
2 changes: 1 addition & 1 deletion src/include/sigtools.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ int checkMutex(uint32_t mask);
int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits);
void adjustregs(x64emu_t* emu, void* pc);

void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, uintptr_t ip);
void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, dynablock_t* db, uintptr_t ip);
#ifdef DYNAREC
void copyEmu2USignalCTXreg(ucontext_t* p, x64emu_t* emu, void* new_pc);
#endif
Expand Down
20 changes: 12 additions & 8 deletions src/libtools/signals.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ void leave_critical_section()
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 my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db, uintptr_t x64pc)
{
int Locks = unlockMutex();
int log_minimum = (BOX64ENV(showsegv))?LOG_NONE:LOG_DEBUG;
Expand Down Expand Up @@ -388,8 +388,12 @@ int my_sigactionhandler_oldcode_64(x64emu_t* emu, int32_t sig, int simple, sigin
void* pc = NULL;
if(p) {
pc = (void*)CONTEXT_PC(p);
if(db)
frame = (uintptr_t)CONTEXT_REG(p, xRSP); //this should not be needed, as emu has been "adjusted" to dynablock value already in the caller
if(db) {
if(ARCH_HOST_CALL(db, pc, x64pc))
frame = R_RSP;
Comment thread
ptitSeb marked this conversation as resolved.
else
frame = (uintptr_t)CONTEXT_REG(p, xRSP); //this should not be needed, as emu has been "adjusted" to dynablock value already in the caller
}
}
#else
(void)ucntx; (void)cur_db;
Expand Down Expand Up @@ -757,7 +761,7 @@ void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo
dynablock_t* db = cur_db;
if(db && ucntx) {
void * pc =(void*)CONTEXT_PC((ucontext_t*)ucntx);
copyUCTXreg2Emu(emu, ucntx, x64pc);
copyUCTXreg2Emu(emu, ucntx, db, x64pc);
adjustregs(emu, pc);
if(db && db->arch_size)
ARCH_ADJUST(db, emu, ucntx, x64pc);
Expand All @@ -769,7 +773,7 @@ void my_sigactionhandler_oldcode(x64emu_t* emu, int32_t sig, int simple, siginfo
direct_ret = my_sigactionhandler_oldcode_32(emu, sig, simple, info, ucntx, old_code, cur_db);
} else
#endif
direct_ret = my_sigactionhandler_oldcode_64(emu, sig, simple, info, ucntx, old_code, cur_db);
direct_ret = my_sigactionhandler_oldcode_64(emu, sig, simple, info, ucntx, old_code, cur_db, x64pc);
if(direct_ret)
return;
#define GO(A) R_##A = old_##A
Expand Down Expand Up @@ -957,7 +961,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
return;
} else {
// dynablock got dirty! need to get out of it!!!
copyUCTXreg2Emu(emu, p, x64pc);
copyUCTXreg2Emu(emu, p, db, x64pc);
// only copy as it's a return address, so there is just the "epilog" to mimic here on "ret" type. "loop" type need everything
if(type_callret) {
adjustregs(emu, pc);
Expand Down Expand Up @@ -1010,7 +1014,7 @@ else dynarec_log(LOG_INFO, "SIGILL at %p/%p for Dynablock (%p, x64addr=%p) with
emu = getEmuSignal(emu, p, db);
// dynablock got auto-dirty! need to get out of it!!!
uintptr_t x64pc = getX64Address(db, (uintptr_t)pc);
copyUCTXreg2Emu(emu, p, x64pc);
copyUCTXreg2Emu(emu, p, db, x64pc);
adjustregs(emu, pc);
if(db && db->arch_size)
ARCH_ADJUST(db, emu, p, x64pc);
Expand Down Expand Up @@ -1258,7 +1262,7 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "%04d|Repeated SIGSEGV with Access error on %
#undef GO
#ifdef DYNAREC
if(db)
copyUCTXreg2Emu(emu, p, x64pc);
copyUCTXreg2Emu(emu, p, db, x64pc);
#endif
nptrs = my_backtrace_ip(emu, buffer, BT_BUF_SIZE);
strings = my_backtrace_symbols(emu, (uintptr_t*)buffer, nptrs);
Expand Down
8 changes: 6 additions & 2 deletions src/libtools/sigtools.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,12 @@ void adjustregs(x64emu_t* emu, void* pc)
#endif
}

void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, uintptr_t ip)
void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, dynablock_t* db, uintptr_t ip)
{
#ifdef DYNAREC
#define GO(R) emu->regs[_##R].q[0] = CONTEXT_REG(p, x##R)
int host_call = p ? ARCH_HOST_CALL(db, (void*)CONTEXT_PC(p), ip) : 0;
#define GO(R) \
if (!host_call) emu->regs[_##R].q[0] = CONTEXT_REG(p, x##R)
GO(RAX);
GO(RCX);
GO(RDX);
Expand All @@ -734,6 +736,8 @@ void copyUCTXreg2Emu(x64emu_t* emu, ucontext_t* p, uintptr_t ip)
GO(RDI);
GO(R8);
GO(R9);
#undef GO
#define GO(R) emu->regs[_##R].q[0] = CONTEXT_REG(p, x##R)
GO(R10);
GO(R11);
GO(R12);
Expand Down
4 changes: 2 additions & 2 deletions src/libtools/syscall_user_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#define AUDIT_ARCH_I386 (EM_386 | __AUDIT_ARCH_LE)
#endif

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 my_sigactionhandler_oldcode_64(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
Expand All @@ -63,7 +63,7 @@ static void sud_emit_sigsys(x64emu_t* emu, uintptr_t call_addr, long syscall_nr,
#else
(void)is32bits;
#endif
my_sigactionhandler_oldcode_64(emu, X64_SIGSYS, 0, &info, NULL, NULL, NULL);
my_sigactionhandler_oldcode_64(emu, X64_SIGSYS, 0, &info, NULL, NULL, NULL, call_addr);
}

long my_syscall_user_dispatch_prctl(x64emu_t* emu, unsigned long op, unsigned long offset, unsigned long len, void* selector)
Expand Down
Loading