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
> Signed-off-by: Florian Hofhammer <[email protected]>
> ---
>  include/plugins/qemu-plugin.h | 13 +++++++++++++
>  plugins/api.c                 | 13 +++++++++++++
>  2 files changed, 26 insertions(+)
>
> diff --git a/include/plugins/qemu-plugin.h b/include/plugins/qemu-plugin.h
> index a6ec8e275d..04c884e82b 100644
> --- a/include/plugins/qemu-plugin.h
> +++ b/include/plugins/qemu-plugin.h
> @@ -76,6 +76,7 @@ typedef uint64_t qemu_plugin_id_t;
>   *
>   * version 6:
>   * - changed return value of qemu_plugin_{read,write}_register from int to 
> bool
> + * - added qemu_plugin_set_pc
>   */
>  
>  extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
> @@ -1042,6 +1043,18 @@ QEMU_PLUGIN_API
>  bool 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 only returns in case of
> + * errors.
> + */
> +QEMU_PLUGIN_API
> +void qemu_plugin_set_pc(uint64_t vaddr);
> +
>  /**
>   * qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
>   *
> diff --git a/plugins/api.c b/plugins/api.c
> index e754b7c69c..ca3e93a194 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"
> @@ -466,6 +467,18 @@ bool qemu_plugin_write_register(struct 
> qemu_plugin_register *reg,
>      return (gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) 
> - 1) > 0);
>  }
>  
> +void qemu_plugin_set_pc(uint64_t vaddr)
> +{
> +    g_assert(current_cpu);
> +
> +    if (qemu_plugin_get_cb_flags() != QEMU_PLUGIN_CB_RW_REGS_PC) {
> +        return;
> +    }

I think its fine to assert() here - we do it elsewhere in the api, if
the user is holding it wrong we should exit now rather than leave the
plugin more confused in the future.

> +
> +    cpu_set_pc(current_cpu, vaddr);
> +    cpu_loop_exit(current_cpu);
> +}
> +
>  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

Reply via email to