mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-08 10:13:56 -06:00
tcg/tci: Implement the disassembler properly
Actually print arguments as opposed to simply the opcodes and, uselessly, the argument counts. Reuse all of the helpers developed as part of the interpreter. Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
65f1b6cc9a
commit
59964b4f98
4 changed files with 284 additions and 64 deletions
283
tcg/tci.c
283
tcg/tci.c
|
@ -1061,3 +1061,286 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disassembler that matches the interpreter
|
||||
*/
|
||||
|
||||
static const char *str_r(TCGReg r)
|
||||
{
|
||||
static const char regs[TCG_TARGET_NB_REGS][4] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "env", "sp"
|
||||
};
|
||||
|
||||
QEMU_BUILD_BUG_ON(TCG_AREG0 != TCG_REG_R14);
|
||||
QEMU_BUILD_BUG_ON(TCG_REG_CALL_STACK != TCG_REG_R15);
|
||||
|
||||
assert((unsigned)r < TCG_TARGET_NB_REGS);
|
||||
return regs[r];
|
||||
}
|
||||
|
||||
static const char *str_c(TCGCond c)
|
||||
{
|
||||
static const char cond[16][8] = {
|
||||
[TCG_COND_NEVER] = "never",
|
||||
[TCG_COND_ALWAYS] = "always",
|
||||
[TCG_COND_EQ] = "eq",
|
||||
[TCG_COND_NE] = "ne",
|
||||
[TCG_COND_LT] = "lt",
|
||||
[TCG_COND_GE] = "ge",
|
||||
[TCG_COND_LE] = "le",
|
||||
[TCG_COND_GT] = "gt",
|
||||
[TCG_COND_LTU] = "ltu",
|
||||
[TCG_COND_GEU] = "geu",
|
||||
[TCG_COND_LEU] = "leu",
|
||||
[TCG_COND_GTU] = "gtu",
|
||||
};
|
||||
|
||||
assert((unsigned)c < ARRAY_SIZE(cond));
|
||||
assert(cond[c][0] != 0);
|
||||
return cond[c];
|
||||
}
|
||||
|
||||
/* Disassemble TCI bytecode. */
|
||||
int print_insn_tci(bfd_vma addr, disassemble_info *info)
|
||||
{
|
||||
uint8_t buf[256];
|
||||
int length, status;
|
||||
const TCGOpDef *def;
|
||||
const char *op_name;
|
||||
TCGOpcode op;
|
||||
TCGReg r0, r1, r2, r3;
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
TCGReg r4, r5;
|
||||
#endif
|
||||
tcg_target_ulong i1;
|
||||
int32_t s2;
|
||||
TCGCond c;
|
||||
TCGMemOpIdx oi;
|
||||
uint8_t pos, len;
|
||||
void *ptr;
|
||||
const uint8_t *tb_ptr;
|
||||
|
||||
status = info->read_memory_func(addr, buf, 2, info);
|
||||
if (status != 0) {
|
||||
info->memory_error_func(status, addr, info);
|
||||
return -1;
|
||||
}
|
||||
op = buf[0];
|
||||
length = buf[1];
|
||||
|
||||
if (length < 2) {
|
||||
info->fprintf_func(info->stream, "invalid length %d", length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = info->read_memory_func(addr + 2, buf + 2, length - 2, info);
|
||||
if (status != 0) {
|
||||
info->memory_error_func(status, addr + 2, info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
def = &tcg_op_defs[op];
|
||||
op_name = def->name;
|
||||
tb_ptr = buf + 2;
|
||||
|
||||
switch (op) {
|
||||
case INDEX_op_br:
|
||||
case INDEX_op_call:
|
||||
case INDEX_op_exit_tb:
|
||||
case INDEX_op_goto_tb:
|
||||
tci_args_l(&tb_ptr, &ptr);
|
||||
info->fprintf_func(info->stream, "%-12s %p", op_name, ptr);
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
tci_args_rrcl(&tb_ptr, &r0, &r1, &c, &ptr);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %p",
|
||||
op_name, str_r(r0), str_r(r1), str_c(c), ptr);
|
||||
break;
|
||||
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_setcond_i64:
|
||||
tci_args_rrrc(&tb_ptr, &r0, &r1, &r2, &c);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2), str_c(c));
|
||||
break;
|
||||
|
||||
case INDEX_op_tci_movi_i32:
|
||||
tci_args_ri(&tb_ptr, &r0, &i1);
|
||||
info->fprintf_func(info->stream, "%-12s %s, 0x%" TCG_PRIlx,
|
||||
op_name, str_r(r0), i1);
|
||||
break;
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
case INDEX_op_tci_movi_i64:
|
||||
tci_args_rI(&tb_ptr, &r0, &i1);
|
||||
info->fprintf_func(info->stream, "%-12s %s, 0x%" TCG_PRIlx,
|
||||
op_name, str_r(r0), i1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INDEX_op_ld8u_i32:
|
||||
case INDEX_op_ld8u_i64:
|
||||
case INDEX_op_ld8s_i32:
|
||||
case INDEX_op_ld8s_i64:
|
||||
case INDEX_op_ld16u_i32:
|
||||
case INDEX_op_ld16u_i64:
|
||||
case INDEX_op_ld16s_i32:
|
||||
case INDEX_op_ld16s_i64:
|
||||
case INDEX_op_ld32u_i64:
|
||||
case INDEX_op_ld32s_i64:
|
||||
case INDEX_op_ld_i32:
|
||||
case INDEX_op_ld_i64:
|
||||
case INDEX_op_st8_i32:
|
||||
case INDEX_op_st8_i64:
|
||||
case INDEX_op_st16_i32:
|
||||
case INDEX_op_st16_i64:
|
||||
case INDEX_op_st32_i64:
|
||||
case INDEX_op_st_i32:
|
||||
case INDEX_op_st_i64:
|
||||
tci_args_rrs(&tb_ptr, &r0, &r1, &s2);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %d",
|
||||
op_name, str_r(r0), str_r(r1), s2);
|
||||
break;
|
||||
|
||||
case INDEX_op_mov_i32:
|
||||
case INDEX_op_mov_i64:
|
||||
case INDEX_op_ext8s_i32:
|
||||
case INDEX_op_ext8s_i64:
|
||||
case INDEX_op_ext8u_i32:
|
||||
case INDEX_op_ext8u_i64:
|
||||
case INDEX_op_ext16s_i32:
|
||||
case INDEX_op_ext16s_i64:
|
||||
case INDEX_op_ext16u_i32:
|
||||
case INDEX_op_ext32s_i64:
|
||||
case INDEX_op_ext32u_i64:
|
||||
case INDEX_op_ext_i32_i64:
|
||||
case INDEX_op_extu_i32_i64:
|
||||
case INDEX_op_bswap16_i32:
|
||||
case INDEX_op_bswap16_i64:
|
||||
case INDEX_op_bswap32_i32:
|
||||
case INDEX_op_bswap32_i64:
|
||||
case INDEX_op_bswap64_i64:
|
||||
case INDEX_op_not_i32:
|
||||
case INDEX_op_not_i64:
|
||||
case INDEX_op_neg_i32:
|
||||
case INDEX_op_neg_i64:
|
||||
tci_args_rr(&tb_ptr, &r0, &r1);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s",
|
||||
op_name, str_r(r0), str_r(r1));
|
||||
break;
|
||||
|
||||
case INDEX_op_add_i32:
|
||||
case INDEX_op_add_i64:
|
||||
case INDEX_op_sub_i32:
|
||||
case INDEX_op_sub_i64:
|
||||
case INDEX_op_mul_i32:
|
||||
case INDEX_op_mul_i64:
|
||||
case INDEX_op_and_i32:
|
||||
case INDEX_op_and_i64:
|
||||
case INDEX_op_or_i32:
|
||||
case INDEX_op_or_i64:
|
||||
case INDEX_op_xor_i32:
|
||||
case INDEX_op_xor_i64:
|
||||
case INDEX_op_div_i32:
|
||||
case INDEX_op_div_i64:
|
||||
case INDEX_op_rem_i32:
|
||||
case INDEX_op_rem_i64:
|
||||
case INDEX_op_divu_i32:
|
||||
case INDEX_op_divu_i64:
|
||||
case INDEX_op_remu_i32:
|
||||
case INDEX_op_remu_i64:
|
||||
case INDEX_op_shl_i32:
|
||||
case INDEX_op_shl_i64:
|
||||
case INDEX_op_shr_i32:
|
||||
case INDEX_op_shr_i64:
|
||||
case INDEX_op_sar_i32:
|
||||
case INDEX_op_sar_i64:
|
||||
case INDEX_op_rotl_i32:
|
||||
case INDEX_op_rotl_i64:
|
||||
case INDEX_op_rotr_i32:
|
||||
case INDEX_op_rotr_i64:
|
||||
tci_args_rrr(&tb_ptr, &r0, &r1, &r2);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2));
|
||||
break;
|
||||
|
||||
case INDEX_op_deposit_i32:
|
||||
case INDEX_op_deposit_i64:
|
||||
tci_args_rrrbb(&tb_ptr, &r0, &r1, &r2, &pos, &len);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %d, %d",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2), pos, len);
|
||||
break;
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
case INDEX_op_setcond2_i32:
|
||||
tci_args_rrrrrc(&tb_ptr, &r0, &r1, &r2, &r3, &r4, &c);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2),
|
||||
str_r(r3), str_r(r4), str_c(c));
|
||||
break;
|
||||
|
||||
case INDEX_op_brcond2_i32:
|
||||
tci_args_rrrrcl(&tb_ptr, &r0, &r1, &r2, &r3, &c, &ptr);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %p",
|
||||
op_name, str_r(r0), str_r(r1),
|
||||
str_r(r2), str_r(r3), str_c(c), ptr);
|
||||
break;
|
||||
|
||||
case INDEX_op_mulu2_i32:
|
||||
tci_args_rrrr(&tb_ptr, &r0, &r1, &r2, &r3);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s",
|
||||
op_name, str_r(r0), str_r(r1),
|
||||
str_r(r2), str_r(r3));
|
||||
break;
|
||||
|
||||
case INDEX_op_add2_i32:
|
||||
case INDEX_op_sub2_i32:
|
||||
tci_args_rrrrrr(&tb_ptr, &r0, &r1, &r2, &r3, &r4, &r5);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2),
|
||||
str_r(r3), str_r(r4), str_r(r5));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INDEX_op_qemu_ld_i64:
|
||||
case INDEX_op_qemu_st_i64:
|
||||
len = DIV_ROUND_UP(64, TCG_TARGET_REG_BITS);
|
||||
goto do_qemu_ldst;
|
||||
case INDEX_op_qemu_ld_i32:
|
||||
case INDEX_op_qemu_st_i32:
|
||||
len = 1;
|
||||
do_qemu_ldst:
|
||||
len += DIV_ROUND_UP(TARGET_LONG_BITS, TCG_TARGET_REG_BITS);
|
||||
switch (len) {
|
||||
case 2:
|
||||
tci_args_rrm(&tb_ptr, &r0, &r1, &oi);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %x",
|
||||
op_name, str_r(r0), str_r(r1), oi);
|
||||
break;
|
||||
case 3:
|
||||
tci_args_rrrm(&tb_ptr, &r0, &r1, &r2, &oi);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %x",
|
||||
op_name, str_r(r0), str_r(r1), str_r(r2), oi);
|
||||
break;
|
||||
case 4:
|
||||
tci_args_rrrrm(&tb_ptr, &r0, &r1, &r2, &r3, &oi);
|
||||
info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %x",
|
||||
op_name, str_r(r0), str_r(r1),
|
||||
str_r(r2), str_r(r3), oi);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
info->fprintf_func(info->stream, "illegal opcode %d", op);
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue