mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
plugins: add PC diversion API function
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 Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Florian Hofhammer <florian.hofhammer@epfl.ch> Link: https://lore.kernel.org/qemu-devel/20260305-setpc-v5-v7-4-4c3adba52403@epfl.ch Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
This commit is contained in:
committed by
Pierrick Bouvier
parent
9097087147
commit
4f55cd7801
@@ -76,6 +76,7 @@ typedef uint64_t qemu_plugin_id_t;
|
|||||||
*
|
*
|
||||||
* version 6:
|
* version 6:
|
||||||
* - changed return value of qemu_plugin_{read,write}_register from int to bool
|
* - 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;
|
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,
|
bool qemu_plugin_write_register(struct qemu_plugin_register *handle,
|
||||||
GByteArray *buf);
|
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
|
||||||
|
__attribute__((__noreturn__))
|
||||||
|
void qemu_plugin_set_pc(uint64_t vaddr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
|
* qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "system/memory.h"
|
#include "system/memory.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
|
#include "exec/cpu-common.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "exec/target_page.h"
|
#include "exec/target_page.h"
|
||||||
#include "exec/translation-block.h"
|
#include "exec/translation-block.h"
|
||||||
@@ -467,6 +468,16 @@ bool qemu_plugin_write_register(struct qemu_plugin_register *reg,
|
|||||||
return (gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1) > 0);
|
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);
|
||||||
|
|
||||||
|
g_assert(qemu_plugin_get_cb_flags() == QEMU_PLUGIN_CB_RW_REGS_PC);
|
||||||
|
|
||||||
|
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)
|
bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len)
|
||||||
{
|
{
|
||||||
g_assert(current_cpu);
|
g_assert(current_cpu);
|
||||||
|
|||||||
@@ -20,9 +20,14 @@ def extract_symbols(plugin_header):
|
|||||||
# Remove QEMU_PLUGIN_API macro definition.
|
# Remove QEMU_PLUGIN_API macro definition.
|
||||||
content = content.replace('#define QEMU_PLUGIN_API', '')
|
content = content.replace('#define QEMU_PLUGIN_API', '')
|
||||||
expected = content.count('QEMU_PLUGIN_API')
|
expected = content.count('QEMU_PLUGIN_API')
|
||||||
# Find last word between QEMU_PLUGIN_API and (, matching on several lines.
|
# Find last word between QEMU_PLUGIN_API and ( to get the function name,
|
||||||
|
# matching on several lines. Discard attributes, if any.
|
||||||
# We use *? non-greedy quantifier.
|
# We use *? non-greedy quantifier.
|
||||||
syms = re.findall(r'QEMU_PLUGIN_API.*?(\w+)\s*\(', content, re.DOTALL)
|
syms = re.findall(
|
||||||
|
r'QEMU_PLUGIN_API\s+(?:__attribute__\(\(\S+\)\))?.*?(\w+)\s*\(',
|
||||||
|
content,
|
||||||
|
re.DOTALL,
|
||||||
|
)
|
||||||
syms.sort()
|
syms.sort()
|
||||||
# Ensure we found as many symbols as API markers.
|
# Ensure we found as many symbols as API markers.
|
||||||
assert len(syms) == expected
|
assert len(syms) == expected
|
||||||
|
|||||||
Reference in New Issue
Block a user