The plugin register API reads env->eflags through the gdbstub.
During TCG execution, arithmetic flags are kept in the lazy CC state
and DF in env->df, so this can return incorrect EFLAGS values.
Add eflags_in_tcg, set on TCG entry and cleared on exit, to select
cpu_compute_eflags() while the flags are split. Also synchronize cc_op
with gen_update_cc_op() before instruction callbacks when plugins are
enabled, since the current value may still be in the translator context.
Outside TCG execution, keep reading env->eflags, which holds the
complete flags. Unconditional reconstruction can use stale lazy state
and break GDB readback: in testing, writing 0x0202 through GDB was
followed by a readback of 0x0203.
Richard Henderson previously proposed EFLAGS reconstruction and cc_op
synchronization for i386 plugin register reads.
Link: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1047061.html
Signed-off-by: Artemii Mashanov <ralerrdirsardx@gmail.com>
---
target/i386/cpu.h | 1 +
target/i386/gdbstub.c | 3 +++
target/i386/tcg/tcg-cpu.c | 2 ++
target/i386/tcg/translate.c | 3 +++
4 files changed, 9 insertions(+)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 9ce8ca0038..b3b4528ea7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2347,6 +2347,7 @@ struct ArchCPU {
CPUState parent_obj;
CPUX86State env;
+ bool eflags_in_tcg;
VMChangeStateEntry *vmsentry;
uint64_t ucode_rev;
diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c
index 5c5fa72721..e636ca0f4a 100644
--- a/target/i386/gdbstub.c
+++ b/target/i386/gdbstub.c
@@ -151,6 +151,9 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case IDX_IP_REG:
return gdb_get_reg(env, mem_buf, env->eip);
case IDX_FLAGS_REG:
+ if (cpu->eflags_in_tcg) {
+ return gdb_get_reg32(mem_buf, cpu_compute_eflags(env));
+ }
return gdb_get_reg32(mem_buf, env->eflags);
case IDX_SEG_REGS:
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 6f5dc06b3b..2402608fe9 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -38,6 +38,7 @@ static void x86_cpu_exec_enter(CPUState *cs)
env->df = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ cpu->eflags_in_tcg = true;
}
static void x86_cpu_exec_exit(CPUState *cs)
@@ -46,6 +47,7 @@ static void x86_cpu_exec_exit(CPUState *cs)
CPUX86State *env = &cpu->env;
env->eflags = cpu_compute_eflags(env);
+ cpu->eflags_in_tcg = false;
}
static TCGTBCPUState x86_get_tb_cpu_state(CPUState *cs)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index d8de290acb..c469d74efe 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3483,6 +3483,9 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
DisasContext *dc = container_of(dcbase, DisasContext, base);
target_ulong pc_arg = dc->base.pc_next;
+ if (dcbase->plugin_enabled) {
+ gen_update_cc_op(dc);
+ }
dc->prev_insn_start = dc->base.insn_start;
dc->prev_insn_end = tcg_last_op();
if (tb_cflags(dcbase->tb) & CF_PCREL) {
base-commit: 257bf4f160c50ca8c4ebd603f519f5c786013fb7
--
2.55.0