[PATCH v4 3/7] plugins: add PC diversion API function

Florian Hofhammer posted 7 patches 1 month, 2 weeks ago
Maintainers: Laurent Vivier <laurent@vivier.eu>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Brian Cain <brian.cain@oss.qualcomm.com>, "Alex Bennée" <alex.bennee@linaro.org>, Alexandre Iooss <erdnaxe@crans.org>, Mahmoud Mandour <ma.mandourr@gmail.com>, Peter Maydell <peter.maydell@linaro.org>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Aurelien Jarno <aurelien@aurel32.net>, Jiaxun Yang <jiaxun.yang@flygoat.com>, Aleksandar Rikalo <arikalo@gmail.com>, Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>, Artyom Tarasenko <atar4qemu@gmail.com>
There is a newer version of this series
[PATCH v4 3/7] plugins: add PC diversion API function
Posted by Florian Hofhammer 1 month, 2 weeks ago
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 <florian.hofhammer@epfl.ch>
---
 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;
+    }
+
+    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);
-- 
2.53.0
Re: [PATCH v4 3/7] plugins: add PC diversion API function
Posted by Alex Bennée 1 month, 2 weeks ago
Florian Hofhammer <florian.hofhammer@epfl.ch> 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 <florian.hofhammer@epfl.ch>
> ---
>  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
Re: [PATCH v4 3/7] plugins: add PC diversion API function
Posted by Pierrick Bouvier 1 month, 2 weeks ago
On 2/24/26 9:46 AM, Alex Bennée wrote:
> Florian Hofhammer <florian.hofhammer@epfl.ch> 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 <florian.hofhammer@epfl.ch>
>> ---
>>   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.
>

Agree.
With the assert instead of return,
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>

Re: [PATCH v4 3/7] plugins: add PC diversion API function
Posted by Florian Hofhammer 1 month, 2 weeks ago
On 24/02/2026 21:12, Pierrick Bouvier wrote:
> On 2/24/26 9:46 AM, Alex Bennée wrote:
>> Florian Hofhammer <florian.hofhammer@epfl.ch> 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 <florian.hofhammer@epfl.ch>
>>> ---
>>>   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.
>>
> 
> Agree.
> With the assert instead of return,
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>

Ack, will update the patch accordingly. Thanks for the feedback!