From: Harry van Haaren <[email protected]>

Executed instructions are cached in string format inside the
execlog plugin. These strings are flushed on exit of a TB, improving
performance. This causes executed instructions to be lost when an
'ecall' (riscv system call) occurs that causes the thread to terminate.

The fix in this patch registers a 'vcpu_exit' callback, and flushes
any content in the c->last_exec buffer, to ensure all instructions are
present in the final instruction log.

Reviewed-by: Pierrick Bouvier <[email protected]>
Tested-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Harry van Haaren <[email protected]>
Link: 
https://lore.kernel.org/qemu-devel/[email protected]
Signed-off-by: Pierrick Bouvier <[email protected]>
---
 contrib/plugins/execlog.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index dfe00bf836c..cb0bd399d88 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -380,6 +380,25 @@ static void vcpu_init(unsigned int vcpu_index, void 
*userdata)
     c->registers = registers_init(vcpu_index);
 }
 
+/**
+ * On vCPU exit, flush the last cached instruction for this vCPU.
+ *
+ * The one-instruction-delay pattern stores each instruction in last_exec and
+ * only prints it when the *next* callback fires. When a thread exits via
+ * syscall (e.g. ecall/exit), no subsequent callback fires for that vCPU and
+ * the final instruction is silently dropped. Flushing here guarantees it is
+ * written before the vCPU is torn down.
+ */
+static void vcpu_exit(unsigned int vcpu_index, void *udata)
+{
+    CPU *c = qemu_plugin_scoreboard_find(cpus, vcpu_index);
+    if (c->last_exec && c->last_exec->len) {
+        g_string_append_c(c->last_exec, '\n');
+        qemu_plugin_outs(c->last_exec->str);
+        g_string_truncate(c->last_exec, 0);
+    }
+}
+
 /**
  * On plugin exit, flush any remaining cached instructions and free state.
  */
@@ -461,6 +480,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t 
id,
     /* Register init, translation block and exit callbacks */
     qemu_plugin_register_vcpu_init_cb(id, vcpu_init, NULL);
     qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans, NULL);
+    qemu_plugin_register_vcpu_exit_cb(id, vcpu_exit, NULL);
     qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
 
     return 0;
-- 
2.47.3


Reply via email to