In addition to the flags specifying whether general-purpose registers are read-write (rw) during a plugin callback, we add an additional flag explicitly stating whether the PC is writable. This is in preparation of a patch that allows to explicitly set the PC to divert control flow from within a plugin callback, which is currently not possible.
Signed-off-by: Florian Hofhammer <[email protected]> --- include/plugins/qemu-plugin.h | 3 +++ plugins/api.c | 3 ++- plugins/core.c | 29 ++++++++++++++++------------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/plugins/qemu-plugin.h b/include/plugins/qemu-plugin.h index 17a834dca9..a6ec8e275d 100644 --- a/include/plugins/qemu-plugin.h +++ b/include/plugins/qemu-plugin.h @@ -325,11 +325,14 @@ typedef struct { * @QEMU_PLUGIN_CB_NO_REGS: callback does not access the CPU's regs * @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs * @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs + * @QEMU_PLUGIN_CB_RW_REGS_PC: callback reads and writes the CPU's + * regs and updates the PC */ enum qemu_plugin_cb_flags { QEMU_PLUGIN_CB_NO_REGS, QEMU_PLUGIN_CB_R_REGS, QEMU_PLUGIN_CB_RW_REGS, + QEMU_PLUGIN_CB_RW_REGS_PC, }; enum qemu_plugin_mem_rw { diff --git a/plugins/api.c b/plugins/api.c index 04ca7da7f1..e754b7c69c 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -458,7 +458,8 @@ bool qemu_plugin_write_register(struct qemu_plugin_register *reg, { g_assert(current_cpu); - if (buf->len == 0 || qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS) { + if (buf->len == 0 || (qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS && + qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS_PC)) { return false; } diff --git a/plugins/core.c b/plugins/core.c index 42fd986593..7220b9dbb4 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -119,7 +119,7 @@ static void plugin_vcpu_cb__discon(CPUState *cpu, struct qemu_plugin_cb *cb, *next; uint64_t to = cpu->cc->get_pc(cpu); - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); if (cpu->cpu_index < plugin.num_vcpus) { /* iterate safely; plugins might uninstall themselves at any time */ QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { @@ -395,15 +395,16 @@ void plugin_register_dyn_cb__udata(GArray **arr, enum qemu_plugin_cb_flags flags, void *udata) { - static TCGHelperInfo info[3] = { + static TCGHelperInfo info[4] = { [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG, [QEMU_PLUGIN_CB_RW_REGS].flags = 0, + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0, /* * Match qemu_plugin_vcpu_udata_cb_t: * void (*)(uint32_t, void *) */ - [0 ... 2].typemask = (dh_typemask(void, 0) | + [0 ... 3].typemask = (dh_typemask(void, 0) | dh_typemask(i32, 1) | dh_typemask(ptr, 2)) }; @@ -425,15 +426,16 @@ void plugin_register_dyn_cond_cb__udata(GArray **arr, uint64_t imm, void *udata) { - static TCGHelperInfo info[3] = { + static TCGHelperInfo info[4] = { [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG, [QEMU_PLUGIN_CB_RW_REGS].flags = 0, + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0, /* * Match qemu_plugin_vcpu_udata_cb_t: * void (*)(uint32_t, void *) */ - [0 ... 2].typemask = (dh_typemask(void, 0) | + [0 ... 3].typemask = (dh_typemask(void, 0) | dh_typemask(i32, 1) | dh_typemask(ptr, 2)) }; @@ -464,15 +466,16 @@ void plugin_register_vcpu_mem_cb(GArray **arr, !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) && !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t)); - static TCGHelperInfo info[3] = { + static TCGHelperInfo info[4] = { [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG, [QEMU_PLUGIN_CB_RW_REGS].flags = 0, + [QEMU_PLUGIN_CB_RW_REGS_PC].flags = 0, /* * Match qemu_plugin_vcpu_mem_cb_t: * void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *) */ - [0 ... 2].typemask = + [0 ... 3].typemask = (dh_typemask(void, 0) | dh_typemask(i32, 1) | (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) @@ -534,7 +537,7 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2, QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_syscall_cb_t func = cb->f.vcpu_syscall; - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7, a8); qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } @@ -558,7 +561,7 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret) QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_syscall_ret_cb_t func = cb->f.vcpu_syscall_ret; - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); func(cb->ctx->id, cpu->cpu_index, num, ret); qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } @@ -584,7 +587,7 @@ qemu_plugin_vcpu_syscall_filter(CPUState *cpu, int64_t num, uint64_t a1, return false; } - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_syscall_filter_cb_t func = cb->f.vcpu_syscall_filter; @@ -605,7 +608,7 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu) { /* idle and resume cb may be called before init, ignore in this case */ if (cpu->cpu_index < plugin.num_vcpus) { - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE); qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } @@ -614,7 +617,7 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu) void qemu_plugin_vcpu_resume_cb(CPUState *cpu) { if (cpu->cpu_index < plugin.num_vcpus) { - qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS_PC); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME); qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } @@ -885,6 +888,6 @@ enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags) } else if (flags & TCG_CALL_NO_WG) { return QEMU_PLUGIN_CB_R_REGS; } else { - return QEMU_PLUGIN_CB_RW_REGS; + return QEMU_PLUGIN_CB_RW_REGS_PC; } } -- 2.53.0
