Florian Hofhammer <[email protected]> writes: > This patch adds a plugin API function that allows diverting the program > counter during execution. A potential use case for this functionality is > to skip over parts of the code, e.g., by hooking into a specific > instruction and setting the PC to the next instruction in the callback. > > Link: > https://lists.nongnu.org/archive/html/qemu-devel/2025-08/msg00656.html
Thanks for taking the time to roll a proper patch. I assume this is working for you OK? If we were to go forward with up-streaming we would want expand a test case to cover the new API. Maybe we could expand the syscall plugin with an option to emulate a system call. > > Signed-off-by: Florian Hofhammer <[email protected]> > --- > include/qemu/qemu-plugin.h | 12 ++++++++++++ > plugins/api.c | 9 +++++++++ > 2 files changed, 21 insertions(+) > > diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h > index c450106af1..fe4e053c52 100644 > --- a/include/qemu/qemu-plugin.h > +++ b/include/qemu/qemu-plugin.h > @@ -943,6 +943,18 @@ QEMU_PLUGIN_API > int qemu_plugin_write_register(struct qemu_plugin_register *handle, > GByteArray *buf); > > +/** > + * qemu_plugin_set_pc() - set the program counter for the current vCPU > + * > + * @vaddr: the new virtual (guest) address for the program counter > + * > + * This function sets the program counter for the current vCPU to @vaddr and > + * resumes execution at that address. This function does not return. > + */ > +QEMU_PLUGIN_API > +G_NORETURN > +void qemu_plugin_set_pc(uint64_t vaddr); > + The current potential foot guns I can see are: - are we called from a callback with QEMU_PLUGIN_CB_RW_REGS - could multiple hooks be wanting to set the PC? Not doing the first could potentially loose you register values which wouldn't be rectified until later in the block. Currently we maintain the list qemu_plugin_insn.insn_cbs in the order they are set. However if the callback that changes the flow is in the middle we risk not calling the others. Currently there is no protection against multiple callbacks wanting to change the flow. Maybe we need a new callback register that implies QEMU_PLUGIN_CB_RW_REGS and we will always ensure is the last cb of the chain? > /** > * qemu_plugin_read_memory_vaddr() - read from memory using a virtual address > * > diff --git a/plugins/api.c b/plugins/api.c > index eac04cc1f6..0511b72ebb 100644 > --- a/plugins/api.c > +++ b/plugins/api.c > @@ -41,6 +41,7 @@ > #include "qemu/log.h" > #include "system/memory.h" > #include "tcg/tcg.h" > +#include "exec/cpu-common.h" > #include "exec/gdbstub.h" > #include "exec/target_page.h" > #include "exec/translation-block.h" > @@ -457,6 +458,14 @@ int qemu_plugin_write_register(struct > qemu_plugin_register *reg, > return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - > 1); > } > > +void qemu_plugin_set_pc(uint64_t vaddr) > +{ > + g_assert(current_cpu); > + > + cpu_set_pc(current_cpu, vaddr); > + cpu_loop_exit(current_cpu); > +} > + As you see the actual mechanics of restarting at the new PC is the easy bit ;-) > bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t > len) > { > g_assert(current_cpu); -- Alex Bennée Virtualisation Tech Lead @ Linaro
