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/[email protected]/msg1047061.html
Signed-off-by: Artemii Mashanov <[email protected]>
---
 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


Reply via email to