Skip to content

Commit

Permalink
[GDBJIT] Display DynaRec info in source file (#2179)
Browse files Browse the repository at this point in the history
* [GDBJIT] Display DynaRec info in source file

* fix
  • Loading branch information
ksco authored Dec 20, 2024
1 parent 291db15 commit 6ac7d7a
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 97 deletions.
187 changes: 101 additions & 86 deletions src/dynarec/arm64/dynarec_arm64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,97 +661,112 @@ const char* getCacheName(int t, int n)

void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if(box64_dynarec_dump) {
printf_x64_instruction(rex.is32bits?my_context->dec32:my_context->dec, &dyn->insts[ninst].x64, name);
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
(box64_dynarec_dump>1)?"\e[32m":"",
(void*)(dyn->native_start+dyn->insts[ninst].address),
dyn->insts[ninst].size/4,
ninst,
dyn->insts[ninst].x64.barrier,
dyn->insts[ninst].x64.state_flags,
dyn->f.pending,
dyn->f.dfnone,
dyn->insts[ninst].f_entry.pending,
dyn->insts[ninst].f_entry.dfnone,
dyn->insts[ninst].f_exit.pending,
dyn->insts[ninst].f_exit.dfnone,
dyn->insts[ninst].x64.may_set?"may":"set",
dyn->insts[ninst].x64.set_flags,
dyn->insts[ninst].x64.gen_flags,
dyn->insts[ninst].x64.use_flags,
dyn->insts[ninst].x64.need_before,
dyn->insts[ninst].x64.need_after,
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
if(dyn->insts[ninst].nat_flags_op) {
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
printf_log(LOG_NONE, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
else
printf_log(LOG_NONE, " NF:%d", dyn->insts[ninst].nat_flags_op);
}
if(dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags)
printf_log(LOG_NONE, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
if(dyn->insts[ninst].invert_carry)
printf_log(LOG_NONE, " CI");
if(dyn->insts[ninst].gen_inverted_carry)
printf_log(LOG_NONE, " gic");
if(dyn->insts[ninst].before_nat_flags&NF_CF)
printf_log(LOG_NONE, " %ccb", dyn->insts[ninst].normal_carry_before?'n':'i');
if(dyn->insts[ninst].need_nat_flags&NF_CF)
printf_log(LOG_NONE, " %cc", dyn->insts[ninst].normal_carry?'n':'i');
if(dyn->insts[ninst].pred_sz) {
dynarec_log(LOG_NONE, ", pred=");
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);
}
if(!dyn->insts[ninst].x64.alive)
dynarec_log(LOG_NONE, " not executed");
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
dynarec_log(LOG_NONE, ", jmp=out");
if(dyn->insts[ninst].x64.has_callret)
dynarec_log(LOG_NONE, ", callret");
if(dyn->last_ip)
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);
for(int ii=0; ii<32; ++ii) {
switch(dyn->insts[ninst].n.neoncache[ii].t) {
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_ST_I64: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_YMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_YMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
//case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_NONE:
default: break;
}
if (!box64_dynarec_dump && !box64_dynarec_gdbjit) return;

static char buf[512];
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
dyn->insts[ninst].x64.barrier,
dyn->insts[ninst].x64.state_flags,
dyn->f.pending,
dyn->f.dfnone,
dyn->insts[ninst].f_entry.pending,
dyn->insts[ninst].f_entry.dfnone,
dyn->insts[ninst].f_exit.pending,
dyn->insts[ninst].f_exit.dfnone,
dyn->insts[ninst].x64.may_set ? "may" : "set",
dyn->insts[ninst].x64.set_flags,
dyn->insts[ninst].x64.gen_flags,
dyn->insts[ninst].x64.use_flags,
dyn->insts[ninst].x64.need_before,
dyn->insts[ninst].x64.need_after,
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
if (dyn->insts[ninst].nat_flags_op) {
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
else
length += sprintf(buf + length, " NF:%d", dyn->insts[ninst].nat_flags_op);
}
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags) {
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
}
if (dyn->insts[ninst].invert_carry)
length += sprintf(buf + length, " CI");
if (dyn->insts[ninst].gen_inverted_carry)
length += sprintf(buf + length, " gic");
if (dyn->insts[ninst].before_nat_flags & NF_CF) {
length += sprintf(buf + length, " %ccb", dyn->insts[ninst].normal_carry_before ? 'n' : 'i');
}
if (dyn->insts[ninst].need_nat_flags & NF_CF) {
length += sprintf(buf + length, " %cc", dyn->insts[ninst].normal_carry ? 'n' : 'i');
}
if (dyn->insts[ninst].pred_sz) {
length += sprintf(buf + length, ", pred=");
for (int ii = 0; ii < dyn->insts[ninst].pred_sz; ++ii)
length += sprintf(buf + length, "%s%d", ii ? "/" : "", dyn->insts[ninst].pred[ii]);
}
if (!dyn->insts[ninst].x64.alive)
length += sprintf(buf + length, "not executed");
if (dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts >= 0) {
length += sprintf(buf + length, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
}
if (dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts == -1)
length += sprintf(buf + length, ", jmp=out");
if (dyn->insts[ninst].x64.has_callret)
length += sprintf(buf + length, ", callret");
if (dyn->last_ip) {
length += sprintf(buf + length, ", last_ip=%p", (void*)dyn->last_ip);
}
for (int ii = 0; ii < 32; ++ii) {
switch (dyn->insts[ninst].n.neoncache[ii].t) {
case NEON_CACHE_ST_D: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_ST_F: length += sprintf(buf + length, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_ST_I64: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_MM: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_XMMW: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_XMMR: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_YMMW: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_YMMR: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
// case NEON_CACHE_SCR: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
case NEON_CACHE_NONE:
default: break;
}
if(memcmp(dyn->insts[ninst].n.neoncache, dyn->n.neoncache, sizeof(dyn->n.neoncache))) {
dynarec_log(LOG_NONE, " %s(Change:", (box64_dynarec_dump>1)?"\e[1;91m":"");
for(int ii=0; ii<32; ++ii) if(dyn->insts[ninst].n.neoncache[ii].v!=dyn->n.neoncache[ii].v) {
dynarec_log(LOG_NONE, " V%d:%s", ii, getCacheName(dyn->n.neoncache[ii].t, dyn->n.neoncache[ii].n));
dynarec_log(LOG_NONE, "->%s", getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n));
}
if (memcmp(dyn->insts[ninst].n.neoncache, dyn->n.neoncache, sizeof(dyn->n.neoncache))) {
length += sprintf(buf + length, " %s(Change:", (box64_dynarec_dump > 1) ? "\e[1;91m" : "");
for (int ii = 0; ii < 32; ++ii)
if (dyn->insts[ninst].n.neoncache[ii].v != dyn->n.neoncache[ii].v) {
length += sprintf(buf + length, " V%d:%s", ii, getCacheName(dyn->n.neoncache[ii].t, dyn->n.neoncache[ii].n));
length += sprintf(buf + length, "->%s", getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n));
}
dynarec_log(LOG_NONE, ")%s", (box64_dynarec_dump>1)?"\e[0;32m":"");
}
if(dyn->insts[ninst].n.ymm_used)
dynarec_log(LOG_NONE, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
if(dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out)
dynarec_log(LOG_NONE, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add ,dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
if(dyn->insts[ninst].purge_ymm)
dynarec_log(LOG_NONE, " purgeYmm=%04x", dyn->insts[ninst].purge_ymm);
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack)
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
length += sprintf(buf + length, ")%s", (box64_dynarec_dump > 1) ? "\e[0;32m" : "");
}
if (dyn->insts[ninst].n.ymm_used) {
length += sprintf(buf + length, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
}
if (dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out) {
length += sprintf(buf + length, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add, dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
}
if (dyn->insts[ninst].purge_ymm) {
length += sprintf(buf + length, " purgeYmm=%04x", dyn->insts[ninst].purge_ymm);
}
if (dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) {
length += sprintf(buf + length, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
}
if (dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
length += sprintf(buf + length, " %s:%d/%d", dyn->insts[ninst].n.swapped ? "SWP" : "CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
}
if (box64_dynarec_dump) {
printf_x64_instruction(rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
(box64_dynarec_dump > 1) ? "\e[32m" : "",
(void*)(dyn->native_start + dyn->insts[ninst].address), dyn->insts[ninst].size / 4, ninst, buf, (box64_dynarec_dump > 1) ? "\e[m" : "");
}
if (box64_dynarec_gdbjit) {
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr) : name;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr, 0) : name;
static char buf2[512];
sprintf(buf2, "; %d: %d opcodes, %s", ninst, dyn->insts[ninst].size / 4, buf);
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), buf2);
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dynarec/dynarec_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
}
} else {
if(dec) {
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX64Trace(dec, inst->addr));
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump > 1) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
} else {
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[01;33m":"", ip);
for(int i=0; i<inst->size; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion src/dynarec/la64/dynarec_la64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
if (box64_dynarec_gdbjit) {
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr) : name;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr, 0) : name;
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dynarec/rv64/dynarec_rv64_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
if (box64_dynarec_gdbjit) {
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr) : name;
const char* inst_name = dec ? DecodeX64Trace(dec, dyn->insts[ninst].x64.addr, 0) : name;
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/emu/x64emu.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,10 @@ void StopEmu(x64emu_t* emu, const char* reason, int is32bits)
#ifdef HAVE_TRACE
if(box64_is32bits) {
if(my_context->dec32)
printf_log(LOG_NONE, "%s\n", DecodeX64Trace(my_context->dec32, emu->old_ip));
printf_log(LOG_NONE, "%s\n", DecodeX64Trace(my_context->dec32, emu->old_ip, 1));
} else {
if(my_context->dec)
printf_log(LOG_NONE, "%s\n", DecodeX64Trace(my_context->dec, emu->old_ip));
printf_log(LOG_NONE, "%s\n", DecodeX64Trace(my_context->dec, emu->old_ip, 1));
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion src/emu/x64run_private.c
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec)
printf_log(LOG_NONE, "%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(*(void**)(ip+11)));
}
} else {
printf_log(LOG_NONE, "%s", DecodeX64Trace(is32bits?my_context->dec32:my_context->dec, ip));
printf_log(LOG_NONE, "%s", DecodeX64Trace(is32bits ? my_context->dec32 : my_context->dec, ip, 1));
uint8_t peek = PK(0);
rex_t rex = {0};
if(!is32bits && peek>=0x40 && peek<=0x4f) {
Expand Down
10 changes: 6 additions & 4 deletions src/emu/x64trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void DeleteX64TraceDecoder(zydis_dec_t **dec)
#endif
}

const char* DecodeX64Trace(zydis_dec_t *dec, uintptr_t p)
const char* DecodeX64Trace(zydis_dec_t* dec, uintptr_t p, int withhex)
{
#ifndef HAVE_TRACE
return "???";
Expand All @@ -138,9 +138,11 @@ const char* DecodeX64Trace(zydis_dec_t *dec, uintptr_t p)
&dec->instruction))) {
char tmp[511];
buff[0]='\0';
for (int i=0; i<dec->instruction.length; ++i) {
sprintf(tmp, "%02X ", *((unsigned char*)p+i));
strcat(buff, tmp);
if (withhex) {
for (int i = 0; i < dec->instruction.length; ++i) {
sprintf(tmp, "%02X ", *((unsigned char*)p + i));
strcat(buff, tmp);
}
}
#if 0
const /*ZydisFormatterToken*/void* token;
Expand Down
2 changes: 1 addition & 1 deletion src/include/x64trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ void DeleteX86TraceDecoder(zydis_dec_t **dec);
zydis_dec_t* InitX64TraceDecoder(box64context_t *context);
void DeleteX64TraceDecoder(zydis_dec_t **dec);

const char* DecodeX64Trace(zydis_dec_t *dec, uintptr_t p);
const char* DecodeX64Trace(zydis_dec_t* dec, uintptr_t p, int withhex);

#endif //__X64TRACE_H_

0 comments on commit 6ac7d7a

Please sign in to comment.