* [RFC PATCH v2 1/7] plugins: add API for registering trap related callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 2/7] plugins: add hooks for new " Julian Ganz
` (7 subsequent siblings)
8 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel
Cc: Julian Ganz, Alex Bennée, Alexandre Iooss, Mahmoud Mandour,
Pierrick Bouvier
The plugin API allows registration of callbacks for a variety of VCPU
related events, such as VCPU reset, idle and resume. However, traps of
any kind, i.e. interrupts or exceptions, were previously not covered.
These kinds of events are arguably quite significant and usually go hand
in hand with a PC discontinuity and, on most platforms, a transition
from some "mode" to another. Thus, plugins for the analysis of
(virtualized) embedded systems may benefit from or even require the
possiblity to perform work on the occurance of an interrupt or
exception.
This change introduces an interface for the registration of trap related
callbacks. Specifically we (loosely) define interrupts, exceptions and
semihosting events across all platforms and introduce one callback for
each type of event. Because possible modes and concepts for enumeration
of traps vary greatly between different architectures the callbacks are
`qemu_plugin_vcpu_simple_cb_t`. That is, they only receive the VCPU id
and may need to call other API functions for retrieving additional
information.
Signed-off-by: Julian Ganz <neither@nut.email>
---
include/qemu/plugin-event.h | 3 +++
include/qemu/qemu-plugin.h | 45 ++++++++++++++++++++++++++++++++++++
plugins/core.c | 18 +++++++++++++++
plugins/qemu-plugins.symbols | 3 +++
4 files changed, 69 insertions(+)
diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
index 7056d8427b..2b69a3821b 100644
--- a/include/qemu/plugin-event.h
+++ b/include/qemu/plugin-event.h
@@ -20,6 +20,9 @@ enum qemu_plugin_event {
QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
QEMU_PLUGIN_EV_FLUSH,
QEMU_PLUGIN_EV_ATEXIT,
+ QEMU_PLUGIN_EV_VCPU_INTERRUPT,
+ QEMU_PLUGIN_EV_VCPU_EXCEPTION,
+ QEMU_PLUGIN_EV_VCPU_SEMIHOSTING,
QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
};
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 622c9a0232..94c3ccd496 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -230,6 +230,51 @@ QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb);
+/**
+ * qemu_plugin_register_vcpu_interrupt_cb() - register a vCPU interrupt callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU receives an interrupt, after the
+ * vCPU was prepared to handle the interrupt. An interrupt, in this context and
+ * across all architectures, is defined as an asynchronous event, usually
+ * originating from outside the CPU. Preparation usually entails updating the PC
+ * to some interrupt handler or trap vector entry.
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_register_vcpu_interrupt_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_exception_cb() - register a vCPU exception callback
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU receives an exception (excluding
+ * semihosting events), after the vCPU was prepared to handle the expection. An
+ * exception, in this context and across all architectures, is defined as a
+ * synchronous event in response to a specific instruction being executed.
+ * Preparation usually entails updating the PC to some exception handler or trap
+ * vector entry.
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_register_vcpu_exception_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb);
+
+/**
+ * qemu_plugin_register_vcpu_semihosting_cb() - register a vCPU semihosting cb
+ * @id: plugin ID
+ * @cb: callback function
+ *
+ * The @cb function is called every time a vCPU encounters a semihosting event,
+ * after the event was handled. A semihosting event can be thought of as a
+ * special kind of exception that is not handled by code run by the vCPU but
+ * machinery outside the vCPU.
+ */
+QEMU_PLUGIN_API
+void qemu_plugin_register_vcpu_semihosting_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb);
+
/** struct qemu_plugin_tb - Opaque handle for a translation block */
struct qemu_plugin_tb;
/** struct qemu_plugin_insn - Opaque handle for a translated instruction */
diff --git a/plugins/core.c b/plugins/core.c
index bb105e8e68..9de997069c 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -559,6 +559,24 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
}
+void qemu_plugin_register_vcpu_interrupt_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb)
+{
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
+}
+
+void qemu_plugin_register_vcpu_exception_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb)
+{
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
+}
+
+void qemu_plugin_register_vcpu_semihosting_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_simple_cb_t cb)
+{
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SEMIHOSTING, cb);
+}
+
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
qemu_plugin_simple_cb_t cb)
{
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index 032661f9ea..449a47af22 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -34,6 +34,9 @@
qemu_plugin_register_vcpu_mem_cb;
qemu_plugin_register_vcpu_mem_inline_per_vcpu;
qemu_plugin_register_vcpu_resume_cb;
+ qemu_plugin_register_vcpu_interrupt_cb;
+ qemu_plugin_register_vcpu_exception_cb;
+ qemu_plugin_register_vcpu_semihosting_cb;
qemu_plugin_register_vcpu_syscall_cb;
qemu_plugin_register_vcpu_syscall_ret_cb;
qemu_plugin_register_vcpu_tb_exec_cb;
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [RFC PATCH v2 2/7] plugins: add hooks for new trap related callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 1/7] plugins: add API for registering trap related callbacks Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API Julian Ganz
` (6 subsequent siblings)
8 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel
Cc: Julian Ganz, Alex Bennée, Alexandre Iooss, Mahmoud Mandour,
Pierrick Bouvier
The plugin API allows registration of callbacks for a variety of VCPU
related events, such as VCPU reset, idle and resume. In addition, we
recently introduced API for registering callbacks for trap events,
specifically for interrupts, exceptions and semihosting events.
This change introduces the corresponding hooks called from target
specific code inside qemu.
Signed-off-by: Julian Ganz <neither@nut.email>
---
include/qemu/plugin.h | 12 ++++++++++++
plugins/core.c | 24 ++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 9726a9ebf3..71f03b83f4 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -160,6 +160,9 @@ void qemu_plugin_vcpu_exit_hook(CPUState *cpu);
void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
+void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu);
+void qemu_plugin_vcpu_exception_cb(CPUState *cpu);
+void qemu_plugin_vcpu_semihosting_cb(CPUState *cpu);
void
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
@@ -242,6 +245,15 @@ static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
{ }
+void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu)
+{ }
+
+void qemu_plugin_vcpu_exception_cb(CPUState *cpu)
+{ }
+
+void qemu_plugin_vcpu_semihosting_cb(CPUState *cpu)
+{ }
+
static inline void
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
diff --git a/plugins/core.c b/plugins/core.c
index 9de997069c..4f80f1cb72 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -100,6 +100,9 @@ static void plugin_vcpu_cb__simple(CPUState *cpu, enum qemu_plugin_event ev)
case QEMU_PLUGIN_EV_VCPU_EXIT:
case QEMU_PLUGIN_EV_VCPU_IDLE:
case QEMU_PLUGIN_EV_VCPU_RESUME:
+ case QEMU_PLUGIN_EV_VCPU_INTERRUPT:
+ case QEMU_PLUGIN_EV_VCPU_EXCEPTION:
+ case QEMU_PLUGIN_EV_VCPU_SEMIHOSTING:
/* iterate safely; plugins might uninstall themselves at any time */
QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
qemu_plugin_vcpu_simple_cb_t func = cb->f.vcpu_simple;
@@ -547,6 +550,27 @@ void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
}
}
+void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu)
+{
+ if (cpu->cpu_index < plugin.num_vcpus) {
+ plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INTERRUPT);
+ }
+}
+
+void qemu_plugin_vcpu_exception_cb(CPUState *cpu)
+{
+ if (cpu->cpu_index < plugin.num_vcpus) {
+ plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXCEPTION);
+ }
+}
+
+void qemu_plugin_vcpu_semihosting_cb(CPUState *cpu)
+{
+ if (cpu->cpu_index < plugin.num_vcpus) {
+ plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_SEMIHOSTING);
+ }
+}
+
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_simple_cb_t cb)
{
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 1/7] plugins: add API for registering trap related callbacks Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 2/7] plugins: add hooks for new " Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-21 18:06 ` Pierrick Bouvier
2024-10-21 18:07 ` Pierrick Bouvier
2024-10-19 16:39 ` [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks Julian Ganz
` (5 subsequent siblings)
8 siblings, 2 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel
Cc: Julian Ganz, Alex Bennée, Alexandre Iooss, Mahmoud Mandour,
Pierrick Bouvier
We recently introduced new plugin API for registration of trap related
callbacks. This change introduces a minimal plugin showcasing the new
API. It simply counts the occurances of interrupts, exceptions and
semihosting events per CPU and reports the counts when exitting.
Signed-off-by: Julian Ganz <neither@nut.email>
---
contrib/plugins/Makefile | 1 +
contrib/plugins/traps.c | 89 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+)
create mode 100644 contrib/plugins/traps.c
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index bbddd4800f..6085fd701f 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -31,6 +31,7 @@ NAMES += drcov
NAMES += ips
NAMES += stoptrigger
NAMES += cflow
+NAMES += traps
ifeq ($(CONFIG_WIN32),y)
SO_SUFFIX := .dll
diff --git a/contrib/plugins/traps.c b/contrib/plugins/traps.c
new file mode 100644
index 0000000000..2a38dbb8b3
--- /dev/null
+++ b/contrib/plugins/traps.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024, Julian Ganz <neither@nut.email>
+ *
+ * Traps - count traps
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+typedef struct {
+ uint64_t interrupts;
+ uint64_t exceptions;
+ uint64_t semihosting;
+ bool active;
+} TrapCounters;
+
+static TrapCounters *traps;
+size_t max_vcpus;
+
+static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ traps[vcpu_index].active = true;
+}
+
+static void vcpu_interrupt(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ traps[vcpu_index].interrupts++;
+}
+
+static void vcpu_exception(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ traps[vcpu_index].exceptions++;
+}
+
+static void vcpu_semihosting(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ traps[vcpu_index].semihosting++;
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_autoptr(GString) report;
+ report = g_string_new("VCPU, interrupts, exceptions, semihosting\n");
+ int vcpu;
+
+ for (vcpu = 0; vcpu < max_vcpus; vcpu++) {
+ TrapCounters *rec = &traps[vcpu];
+ if (rec->active) {
+ g_string_append_printf(report,
+ "% 4d, % 10"PRId64", % 10"PRId64", % 10"
+ PRId64"\n",
+ vcpu,
+ rec->interrupts, rec->exceptions,
+ rec->semihosting);
+ }
+ }
+
+ qemu_plugin_outs(report->str);
+}
+
+QEMU_PLUGIN_EXPORT
+int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
+ int argc, char **argv)
+{
+ if (!info->system_emulation) {
+ fputs("trap plugin can only be used in system emulation mode.\n",
+ stderr);
+ return -1;
+ }
+
+ max_vcpus = info->system.max_vcpus;
+ traps = calloc(max_vcpus, sizeof(TrapCounters));
+ qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
+ qemu_plugin_vcpu_for_each(id, vcpu_init);
+
+ qemu_plugin_register_vcpu_interrupt_cb(id, vcpu_interrupt);
+ qemu_plugin_register_vcpu_exception_cb(id, vcpu_exception);
+ qemu_plugin_register_vcpu_semihosting_cb(id, vcpu_semihosting);
+
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+
+ return 0;
+}
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API
2024-10-19 16:39 ` [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API Julian Ganz
@ 2024-10-21 18:06 ` Pierrick Bouvier
2024-10-21 18:07 ` Pierrick Bouvier
1 sibling, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-21 18:06 UTC (permalink / raw)
To: Julian Ganz, qemu-devel
Cc: Alex Bennée, Alexandre Iooss, Mahmoud Mandour
On 10/19/24 09:39, Julian Ganz wrote:
> We recently introduced new plugin API for registration of trap related
> callbacks. This change introduces a minimal plugin showcasing the new
> API. It simply counts the occurances of interrupts, exceptions and
> semihosting events per CPU and reports the counts when exitting.
>
> Signed-off-by: Julian Ganz <neither@nut.email>
> ---
> contrib/plugins/Makefile | 1 +
> contrib/plugins/traps.c | 89 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 90 insertions(+)
> create mode 100644 contrib/plugins/traps.c
>
> diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
> index bbddd4800f..6085fd701f 100644
> --- a/contrib/plugins/Makefile
> +++ b/contrib/plugins/Makefile
> @@ -31,6 +31,7 @@ NAMES += drcov
> NAMES += ips
> NAMES += stoptrigger
> NAMES += cflow
> +NAMES += traps
>
> ifeq ($(CONFIG_WIN32),y)
> SO_SUFFIX := .dll
> diff --git a/contrib/plugins/traps.c b/contrib/plugins/traps.c
> new file mode 100644
> index 0000000000..2a38dbb8b3
> --- /dev/null
> +++ b/contrib/plugins/traps.c
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (C) 2024, Julian Ganz <neither@nut.email>
> + *
> + * Traps - count traps
> + *
> + * License: GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include <stdio.h>
> +
> +#include <qemu-plugin.h>
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> +
> +typedef struct {
> + uint64_t interrupts;
> + uint64_t exceptions;
> + uint64_t semihosting;
> + bool active;
> +} TrapCounters;
> +
> +static TrapCounters *traps;
> +size_t max_vcpus;
> +
> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].active = true;
> +}
> +
> +static void vcpu_interrupt(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].interrupts++;
> +}
> +
> +static void vcpu_exception(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].exceptions++;
> +}
> +
> +static void vcpu_semihosting(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].semihosting++;
> +}
> +
> +static void plugin_exit(qemu_plugin_id_t id, void *p)
> +{
> + g_autoptr(GString) report;
> + report = g_string_new("VCPU, interrupts, exceptions, semihosting\n");
> + int vcpu;
> +
> + for (vcpu = 0; vcpu < max_vcpus; vcpu++) {
> + TrapCounters *rec = &traps[vcpu];
> + if (rec->active) {
> + g_string_append_printf(report,
> + "% 4d, % 10"PRId64", % 10"PRId64", % 10"
> + PRId64"\n",
> + vcpu,
> + rec->interrupts, rec->exceptions,
> + rec->semihosting);
> + }
> + }
> +
> + qemu_plugin_outs(report->str);
> +}
> +
> +QEMU_PLUGIN_EXPORT
> +int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
> + int argc, char **argv)
> +{
> + if (!info->system_emulation) {
> + fputs("trap plugin can only be used in system emulation mode.\n",
> + stderr);
> + return -1;
> + }
> +
> + max_vcpus = info->system.max_vcpus;
> + traps = calloc(max_vcpus, sizeof(TrapCounters));
> + qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
> + qemu_plugin_vcpu_for_each(id, vcpu_init);
> +
> + qemu_plugin_register_vcpu_interrupt_cb(id, vcpu_interrupt);
> + qemu_plugin_register_vcpu_exception_cb(id, vcpu_exception);
> + qemu_plugin_register_vcpu_semihosting_cb(id, vcpu_semihosting);
> +
> + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
> +
> + return 0;
> +
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API
2024-10-19 16:39 ` [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API Julian Ganz
2024-10-21 18:06 ` Pierrick Bouvier
@ 2024-10-21 18:07 ` Pierrick Bouvier
2024-10-21 20:22 ` Julian Ganz
1 sibling, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-21 18:07 UTC (permalink / raw)
To: Julian Ganz, qemu-devel
Cc: Alex Bennée, Alexandre Iooss, Mahmoud Mandour
On 10/19/24 09:39, Julian Ganz wrote:
> We recently introduced new plugin API for registration of trap related
> callbacks. This change introduces a minimal plugin showcasing the new
> API. It simply counts the occurances of interrupts, exceptions and
> semihosting events per CPU and reports the counts when exitting.
>
> Signed-off-by: Julian Ganz <neither@nut.email>
> ---
> contrib/plugins/Makefile | 1 +
> contrib/plugins/traps.c | 89 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 90 insertions(+)
> create mode 100644 contrib/plugins/traps.c
>
> diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
> index bbddd4800f..6085fd701f 100644
> --- a/contrib/plugins/Makefile
> +++ b/contrib/plugins/Makefile
> @@ -31,6 +31,7 @@ NAMES += drcov
> NAMES += ips
> NAMES += stoptrigger
> NAMES += cflow
> +NAMES += traps
>
> ifeq ($(CONFIG_WIN32),y)
> SO_SUFFIX := .dll
> diff --git a/contrib/plugins/traps.c b/contrib/plugins/traps.c
> new file mode 100644
> index 0000000000..2a38dbb8b3
> --- /dev/null
> +++ b/contrib/plugins/traps.c
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (C) 2024, Julian Ganz <neither@nut.email>
> + *
> + * Traps - count traps
> + *
> + * License: GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include <stdio.h>
> +
> +#include <qemu-plugin.h>
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> +
> +typedef struct {
> + uint64_t interrupts;
> + uint64_t exceptions;
> + uint64_t semihosting;
> + bool active;
> +} TrapCounters;
> +
> +static TrapCounters *traps;
> +size_t max_vcpus;
> +
> +static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].active = true;
> +}
> +
> +static void vcpu_interrupt(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].interrupts++;
> +}
> +
> +static void vcpu_exception(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].exceptions++;
> +}
> +
> +static void vcpu_semihosting(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> + traps[vcpu_index].semihosting++;
> +}
> +
> +static void plugin_exit(qemu_plugin_id_t id, void *p)
> +{
> + g_autoptr(GString) report;
> + report = g_string_new("VCPU, interrupts, exceptions, semihosting\n");
> + int vcpu;
> +
> + for (vcpu = 0; vcpu < max_vcpus; vcpu++) {
> + TrapCounters *rec = &traps[vcpu];
> + if (rec->active) {
> + g_string_append_printf(report,
> + "% 4d, % 10"PRId64", % 10"PRId64", % 10"
> + PRId64"\n",
> + vcpu,
> + rec->interrupts, rec->exceptions,
> + rec->semihosting);
> + }
> + }
> +
> + qemu_plugin_outs(report->str);
> +}
> +
> +QEMU_PLUGIN_EXPORT
> +int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
> + int argc, char **argv)
> +{
> + if (!info->system_emulation) {
> + fputs("trap plugin can only be used in system emulation mode.\n",
> + stderr);
> + return -1;
> + }
> +
> + max_vcpus = info->system.max_vcpus;
> + traps = calloc(max_vcpus, sizeof(TrapCounters));
Instead of allocating data for max number of vcpu, you can use a
qemu_plugin_scoreboard, which was introduced recently, and covers
exactly this need, by providing an array that gets automatically
redimensioned when a vcpu is added.
A simple example using it can be found with bb plugin:
https://gitlab.com/qemu-project/qemu/-/blob/master/tests/tcg/plugins/bb.c
> + qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
> + qemu_plugin_vcpu_for_each(id, vcpu_init);
> +
> + qemu_plugin_register_vcpu_interrupt_cb(id, vcpu_interrupt);
> + qemu_plugin_register_vcpu_exception_cb(id, vcpu_exception);
> + qemu_plugin_register_vcpu_semihosting_cb(id, vcpu_semihosting);
> +
> + qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
> +
> + return 0;
> +}
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API
2024-10-21 18:07 ` Pierrick Bouvier
@ 2024-10-21 20:22 ` Julian Ganz
0 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-21 20:22 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Cc: Alex Bennée, Alexandre Iooss, Mahmoud Mandour
October 21, 2024 at 8:07 PM, "Pierrick Bouvier" wrote:
> On 10/19/24 09:39, Julian Ganz wrote:
> > + max_vcpus = info->system.max_vcpus;
> > + traps = calloc(max_vcpus, sizeof(TrapCounters));
> >
> Instead of allocating data for max number of vcpu, you can use a qemu_plugin_scoreboard, which was introduced recently, and covers exactly this need, by providing an array that gets automatically redimensioned when a vcpu is added.
>
> A simple example using it can be found with bb plugin:
> https://gitlab.com/qemu-project/qemu/-/blob/master/tests/tcg/plugins/b(id, vb.c
Thanks for pointing this out! I scrolled past the scoreboard API at least once without realizing what it was.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (2 preceding siblings ...)
2024-10-19 16:39 ` [RFC PATCH v2 3/7] contrib/plugins: add plugin showcasing new trap related API Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-21 12:58 ` Peter Maydell
2024-10-19 16:39 ` [RFC PATCH v2 5/7] target/avr: " Julian Ganz
` (4 subsequent siblings)
8 siblings, 1 reply; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel; +Cc: Julian Ganz, Peter Maydell, open list:ARM TCG CPUs
We recently introduced API for registering callbacks for trap related
events as well as the corresponding hook functions. Due to differences
between architectures, the latter need to be called from target specific
code.
This change places hooks for ARM (and Aarch64) targets. We decided to
treat the (V)IRQ, (VI/VF)NMI, (V)FIQ and VSERR exceptions as interrupts
since they are, presumably, async in nature.
Signed-off-by: Julian Ganz <neither@nut.email>
---
target/arm/helper.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0a731a38e8..f636e216c8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -31,6 +31,7 @@
#endif
#include "cpregs.h"
#include "target/arm/gtimer.h"
+#include "qemu/plugin.h"
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
@@ -11147,6 +11148,24 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
}
}
+static void arm_do_plugin_vcpu_interrupt_cb(CPUState *cs)
+{
+ switch (cs->exception_index) {
+ case EXCP_IRQ:
+ case EXCP_VIRQ:
+ case EXCP_NMI:
+ case EXCP_VINMI:
+ case EXCP_FIQ:
+ case EXCP_VFIQ:
+ case EXCP_VFNMI:
+ case EXCP_VSERR:
+ qemu_plugin_vcpu_interrupt_cb(cs);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs);
+ }
+}
+
static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
{
/*
@@ -11819,6 +11838,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
+ arm_do_plugin_vcpu_interrupt_cb(cs);
return;
}
@@ -11830,6 +11850,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
#ifdef CONFIG_TCG
if (cs->exception_index == EXCP_SEMIHOST) {
tcg_handle_semihosting(cs);
+ qemu_plugin_vcpu_semihosting_cb(cs);
return;
}
#endif
@@ -11855,6 +11876,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
if (!kvm_enabled()) {
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
+
+ arm_do_plugin_vcpu_interrupt_cb(cs);
}
#endif /* !CONFIG_USER_ONLY */
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks Julian Ganz
@ 2024-10-21 12:58 ` Peter Maydell
2024-10-21 16:25 ` Julian Ganz
0 siblings, 1 reply; 35+ messages in thread
From: Peter Maydell @ 2024-10-21 12:58 UTC (permalink / raw)
To: Julian Ganz; +Cc: qemu-devel, open list:ARM TCG CPUs
On Sat, 19 Oct 2024 at 17:39, Julian Ganz <neither@nut.email> wrote:
>
> We recently introduced API for registering callbacks for trap related
> events as well as the corresponding hook functions. Due to differences
> between architectures, the latter need to be called from target specific
> code.
>
> This change places hooks for ARM (and Aarch64) targets. We decided to
> treat the (V)IRQ, (VI/VF)NMI, (V)FIQ and VSERR exceptions as interrupts
> since they are, presumably, async in nature.
>
> Signed-off-by: Julian Ganz <neither@nut.email>
> ---
> target/arm/helper.c | 23 +++++++++++++++++++++++
> 1 file changed, 23 insertions(+)
This omits M-profile Arm CPUs (whose interrupt/exception
handling is rather more complicated, and lives in
m_helper.c.)
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 0a731a38e8..f636e216c8 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -31,6 +31,7 @@
> #endif
> #include "cpregs.h"
> #include "target/arm/gtimer.h"
> +#include "qemu/plugin.h"
>
> #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
>
> @@ -11147,6 +11148,24 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
> }
> }
>
> +static void arm_do_plugin_vcpu_interrupt_cb(CPUState *cs)
> +{
> + switch (cs->exception_index) {
> + case EXCP_IRQ:
> + case EXCP_VIRQ:
> + case EXCP_NMI:
> + case EXCP_VINMI:
> + case EXCP_FIQ:
> + case EXCP_VFIQ:
> + case EXCP_VFNMI:
> + case EXCP_VSERR:
> + qemu_plugin_vcpu_interrupt_cb(cs);
> + break;
> + default:
> + qemu_plugin_vcpu_exception_cb(cs);
> + }
> +}
> +
> static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
> {
> /*
> @@ -11819,6 +11838,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
> arm_handle_psci_call(cpu);
> qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
> + arm_do_plugin_vcpu_interrupt_cb(cs);
This isn't really an interrupt or exception -- it's
more like the semihosting, where the guest does an HVC
or SMC instruction and QEMU handles it by emulating it
as if it were firmware. Maybe it would be better to
name the "semihosting" plugin callbacks something more
generic and include this kind of case in them ?
> return;
> }
>
> @@ -11830,6 +11850,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> #ifdef CONFIG_TCG
> if (cs->exception_index == EXCP_SEMIHOST) {
> tcg_handle_semihosting(cs);
> + qemu_plugin_vcpu_semihosting_cb(cs);
> return;
> }
> #endif
> @@ -11855,6 +11876,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
> if (!kvm_enabled()) {
> cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> }
> +
> + arm_do_plugin_vcpu_interrupt_cb(cs);
thanks
-- PMM
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks
2024-10-21 12:58 ` Peter Maydell
@ 2024-10-21 16:25 ` Julian Ganz
0 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-21 16:25 UTC (permalink / raw)
To: Peter Maydell, Julian Ganz; +Cc: qemu-devel, open list:ARM TCG CPUs
Thanks for the quick reply!
October 21, 2024 at 2:58 PM, Peter Maydell wrote:
> This omits M-profile Arm CPUs (whose interrupt/exception
> handling is rather more complicated, and lives in
> m_helper.c.)
Yes, I forgot about the M-profile. I'll include those changes wiith the
next patch-series.
> > @@ -11819,6 +11838,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
> > if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
> > arm_handle_psci_call(cpu);
> > qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
> > + arm_do_plugin_vcpu_interrupt_cb(cs);
> >
> This isn't really an interrupt or exception -- it's
> more like the semihosting, where the guest does an HVC
> or SMC instruction and QEMU handles it by emulating it
> as if it were firmware. Maybe it would be better to
> name the "semihosting" plugin callbacks something more
> generic and include this kind of case in them ?
Oh, good to know. The only term for something like this (which also
includes semihosting) that comes to mind would be "host call". But that
may be confusing when talking about emulated vs simulated hypervisors?
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC PATCH v2 5/7] target/avr: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (3 preceding siblings ...)
2024-10-19 16:39 ` [RFC PATCH v2 4/7] target/arm: call plugin trap callbacks Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-19 17:29 ` Michael Rolnik
2024-10-19 16:39 ` [RFC PATCH v2 6/7] target/riscv: " Julian Ganz
` (3 subsequent siblings)
8 siblings, 1 reply; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel; +Cc: Julian Ganz, Michael Rolnik
We recently introduced API for registering callbacks for trap related
events as well as the corresponding hook functions. Due to differences
between architectures, the latter need to be called from target specific
code.
This change places the hook for AVR targets. That architecture appears
to only know interrupts.
Signed-off-by: Julian Ganz <neither@nut.email>
---
target/avr/helper.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/target/avr/helper.c b/target/avr/helper.c
index 345708a1b3..be94552674 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -28,6 +28,7 @@
#include "exec/cpu_ldst.h"
#include "exec/address-spaces.h"
#include "exec/helper-proto.h"
+#include "qemu/plugin.h"
bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
@@ -97,6 +98,8 @@ void avr_cpu_do_interrupt(CPUState *cs)
env->sregI = 0; /* clear Global Interrupt Flag */
cs->exception_index = -1;
+
+ qemu_plugin_vcpu_interrupt_cb(cs);
}
hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 5/7] target/avr: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 5/7] target/avr: " Julian Ganz
@ 2024-10-19 17:29 ` Michael Rolnik
0 siblings, 0 replies; 35+ messages in thread
From: Michael Rolnik @ 2024-10-19 17:29 UTC (permalink / raw)
To: Julian Ganz; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1319 bytes --]
Reviewed-by: Michael Rolnik <mrolnik@gmail.com>
On Sat, Oct 19, 2024 at 7:39 PM Julian Ganz <neither@nut.email> wrote:
> We recently introduced API for registering callbacks for trap related
> events as well as the corresponding hook functions. Due to differences
> between architectures, the latter need to be called from target specific
> code.
>
> This change places the hook for AVR targets. That architecture appears
> to only know interrupts.
>
> Signed-off-by: Julian Ganz <neither@nut.email>
> ---
> target/avr/helper.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/target/avr/helper.c b/target/avr/helper.c
> index 345708a1b3..be94552674 100644
> --- a/target/avr/helper.c
> +++ b/target/avr/helper.c
> @@ -28,6 +28,7 @@
> #include "exec/cpu_ldst.h"
> #include "exec/address-spaces.h"
> #include "exec/helper-proto.h"
> +#include "qemu/plugin.h"
>
> bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> {
> @@ -97,6 +98,8 @@ void avr_cpu_do_interrupt(CPUState *cs)
> env->sregI = 0; /* clear Global Interrupt Flag */
>
> cs->exception_index = -1;
> +
> + qemu_plugin_vcpu_interrupt_cb(cs);
> }
>
> hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
> --
> 2.45.2
>
>
--
Best Regards,
Michael Rolnik
[-- Attachment #2: Type: text/html, Size: 1859 bytes --]
^ permalink raw reply [flat|nested] 35+ messages in thread
* [RFC PATCH v2 6/7] target/riscv: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (4 preceding siblings ...)
2024-10-19 16:39 ` [RFC PATCH v2 5/7] target/avr: " Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-19 16:39 ` [RFC PATCH v2 7/7] target/sparc: " Julian Ganz
` (2 subsequent siblings)
8 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel
Cc: Julian Ganz, Palmer Dabbelt, Alistair Francis, Bin Meng,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei,
open list:RISC-V TCG CPUs
We recently introduced API for registering callbacks for trap related
events as well as the corresponding hook functions. Due to differences
between architectures, the latter need to be called from target specific
code.
This change places hooks for RISC-V targets.
Signed-off-by: Julian Ganz <neither@nut.email>
---
target/riscv/cpu_helper.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a935377b4a..2a95869339 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -33,6 +33,7 @@
#include "cpu_bits.h"
#include "debug.h"
#include "tcg/oversized-guest.h"
+#include "qemu/plugin.h"
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -1678,6 +1679,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
case RISCV_EXCP_SEMIHOST:
do_common_semihosting(cs);
env->pc += 4;
+ qemu_plugin_vcpu_semihosting_cb(cs);
return;
#endif
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
@@ -1839,6 +1841,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
riscv_cpu_set_mode(env, PRV_M, virt);
}
+ if (async) {
+ qemu_plugin_vcpu_interrupt_cb(cs);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs);
+ }
+
/*
* NOTE: it is not necessary to yield load reservations here. It is only
* necessary for an SC from "another hart" to cause a load reservation
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [RFC PATCH v2 7/7] target/sparc: call plugin trap callbacks
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (5 preceding siblings ...)
2024-10-19 16:39 ` [RFC PATCH v2 6/7] target/riscv: " Julian Ganz
@ 2024-10-19 16:39 ` Julian Ganz
2024-10-20 19:37 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps Alex Bennée
2024-10-21 18:00 ` Pierrick Bouvier
8 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-19 16:39 UTC (permalink / raw)
To: qemu-devel; +Cc: Julian Ganz, Mark Cave-Ayland, Artyom Tarasenko
We recently introduced API for registering callbacks for trap related
events as well as the corresponding hook functions. Due to differences
between architectures, the latter need to be called from target specific
code.
This change places hooks for SPARC (32bit and 64bit) targets. We treat
any interrupt other than EXTINT and IVEC as exceptions as they appear to
be synchroneous events. Also note that SPARC targets do not have
semihosting events.
Signed-off-by: Julian Ganz <neither@nut.email>
---
target/sparc/int32_helper.c | 7 +++++++
target/sparc/int64_helper.c | 10 ++++++++++
2 files changed, 17 insertions(+)
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index f2dd8bcb2e..4eb41694f7 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -24,6 +24,7 @@
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "sysemu/runstate.h"
+#include "qemu/plugin.h"
static const char * const excp_names[0x80] = {
[TT_TFAULT] = "Instruction Access Fault",
@@ -172,4 +173,10 @@ void sparc_cpu_do_interrupt(CPUState *cs)
env->qemu_irq_ack(env, intno);
}
#endif
+
+ if (intno == TT_EXTINT) {
+ qemu_plugin_vcpu_interrupt_cb(cs);
+ } else {
+ qemu_plugin_vcpu_exception_cb(cs);
+ }
}
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index bd14c7a0db..f4175ef912 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -23,6 +23,7 @@
#include "exec/helper-proto.h"
#include "exec/log.h"
#include "trace.h"
+#include "qemu/plugin.h"
#define DEBUG_PCALL
@@ -253,6 +254,15 @@ void sparc_cpu_do_interrupt(CPUState *cs)
}
env->npc = env->pc + 4;
cs->exception_index = -1;
+
+ switch (intno) {
+ case TT_EXTINT:
+ case TT_IVEC:
+ qemu_plugin_vcpu_interrupt_cb(cs);
+ break;
+ default:
+ qemu_plugin_vcpu_exception_cb(cs);
+ }
}
trap_state *cpu_tsptr(CPUSPARCState* env)
--
2.45.2
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (6 preceding siblings ...)
2024-10-19 16:39 ` [RFC PATCH v2 7/7] target/sparc: " Julian Ganz
@ 2024-10-20 19:37 ` Alex Bennée
2024-10-21 18:00 ` Pierrick Bouvier
8 siblings, 0 replies; 35+ messages in thread
From: Alex Bennée @ 2024-10-20 19:37 UTC (permalink / raw)
To: Julian Ganz; +Cc: qemu-devel
Julian Ganz <neither@nut.email> writes:
> Some analysis greatly benefits, or depends on, information about
> interrupts. For example, we may need to handle the execution of a new
> translation block differently if it is not the result of normal program
> flow but of an interrupt.
For future iterations please post as a new series as tagging onto an old
series will confuse tooling like patchew. I shall try and get around to
reviewing later this week.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-19 16:39 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks " Julian Ganz
` (7 preceding siblings ...)
2024-10-20 19:37 ` [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps Alex Bennée
@ 2024-10-21 18:00 ` Pierrick Bouvier
2024-10-21 18:47 ` Alex Bennée
2024-10-21 21:02 ` Julian Ganz
8 siblings, 2 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-21 18:00 UTC (permalink / raw)
To: Julian Ganz, qemu-devel
Hi Julian,
On 10/19/24 09:39, Julian Ganz wrote:
> Some analysis greatly benefits, or depends on, information about
> interrupts. For example, we may need to handle the execution of a new
> translation block differently if it is not the result of normal program
> flow but of an interrupt.
>
> Even with the existing interfaces, it is more or less possible to
> discern these situations, e.g. as done by the cflow plugin. However,
> this process poses a considerable overhead to the core analysis one may
> intend to perform.
>
I agree it would be useful. Beyond the scope of this series, it would be
nice if we could add a control flow related API instead of asking to
plugins to do it themselves.
If we would provide something like this, is there still a value to add
an API to detect interrupt/exceptions/traps events?
Note: It's not a critic against what you sent, just an open question on
*why* it's useful to access this QEMU implementation related information
vs something more generic.
> These changes introduce a generic and easy-to-use interface for plugin
> authors in the form of callbacks for different types of traps. Patch 1
> defines the callback registration functions and supplies a somewhat
> narrow definition of the event the callbacks are called. Patch 2 adds
> some hooks for triggering the callbacks. Patch 3 adds an example plugin
> showcasing the new API. The remaining patches call the hooks for a
> selection of architectures, mapping architecture specific events to the
> three categories defined in patch 1. Future non-RFC patchsets will call
> these hooks for all architectures (that have some concept of trap or
> interrupt).
>
> Sidenote: I'm likely doing something wrong for one architecture or
> the other. For example, with the old version Alex Bennée suggested
> registering a helper function with arm_register_el_change_hook() for
> arm, which is not what I ended up doing. And for AVR my approach to just
> assume only (asynchroneous) interrupts exist is also likely too naïve.
>
> Since v1:
> - Split the one callback into multiple callbacks
> - Added a target-agnostic definition of the relevant event(s)
> - Call hooks from architecture-code rather than accel/tcg/cpu-exec.c
> - Added a plugin showcasing API usage
>
> Julian Ganz (7):
> plugins: add API for registering trap related callbacks
> plugins: add hooks for new trap related callbacks
> contrib/plugins: add plugin showcasing new trap related API
> target/arm: call plugin trap callbacks
> target/avr: call plugin trap callbacks
> target/riscv: call plugin trap callbacks
> target/sparc: call plugin trap callbacks
>
> contrib/plugins/Makefile | 1 +
> contrib/plugins/traps.c | 89 ++++++++++++++++++++++++++++++++++++
> include/qemu/plugin-event.h | 3 ++
> include/qemu/plugin.h | 12 +++++
> include/qemu/qemu-plugin.h | 45 ++++++++++++++++++
> plugins/core.c | 42 +++++++++++++++++
> plugins/qemu-plugins.symbols | 3 ++
> target/arm/helper.c | 23 ++++++++++
> target/avr/helper.c | 3 ++
> target/riscv/cpu_helper.c | 8 ++++
> target/sparc/int32_helper.c | 7 +++
> target/sparc/int64_helper.c | 10 ++++
> 12 files changed, 246 insertions(+)
> create mode 100644 contrib/plugins/traps.c
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-21 18:00 ` Pierrick Bouvier
@ 2024-10-21 18:47 ` Alex Bennée
2024-10-21 20:45 ` Pierrick Bouvier
2024-10-21 21:02 ` Julian Ganz
1 sibling, 1 reply; 35+ messages in thread
From: Alex Bennée @ 2024-10-21 18:47 UTC (permalink / raw)
To: Pierrick Bouvier; +Cc: Julian Ganz, qemu-devel
Pierrick Bouvier <pierrick.bouvier@linaro.org> writes:
> Hi Julian,
>
> On 10/19/24 09:39, Julian Ganz wrote:
>> Some analysis greatly benefits, or depends on, information about
>> interrupts. For example, we may need to handle the execution of a new
>> translation block differently if it is not the result of normal program
>> flow but of an interrupt.
>> Even with the existing interfaces, it is more or less possible to
>> discern these situations, e.g. as done by the cflow plugin. However,
>> this process poses a considerable overhead to the core analysis one may
>> intend to perform.
>>
>
> I agree it would be useful. Beyond the scope of this series, it would
> be nice if we could add a control flow related API instead of asking
> to plugins to do it themselves.
I think there is a balance to be had here. We don't want to
inadvertently expose QEMU internals to the plugin API. With this series
at least we rely on stuff the front-end knows which can at least be
tweaked relatively easily.
> If we would provide something like this, is there still a value to add
> an API to detect interrupt/exceptions/traps events?
>
> Note: It's not a critic against what you sent, just an open question
> on *why* it's useful to access this QEMU implementation related
> information vs something more generic.
<snip>
It would be good to have the opinion of the front-end maintainers if
this is too burdensome or easy enough to manage.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-21 18:47 ` Alex Bennée
@ 2024-10-21 20:45 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-21 20:45 UTC (permalink / raw)
To: Alex Bennée; +Cc: Julian Ganz, qemu-devel
On 10/21/24 11:47, Alex Bennée wrote:
> Pierrick Bouvier <pierrick.bouvier@linaro.org> writes:
>
>> Hi Julian,
>>
>> On 10/19/24 09:39, Julian Ganz wrote:
>>> Some analysis greatly benefits, or depends on, information about
>>> interrupts. For example, we may need to handle the execution of a new
>>> translation block differently if it is not the result of normal program
>>> flow but of an interrupt.
>>> Even with the existing interfaces, it is more or less possible to
>>> discern these situations, e.g. as done by the cflow plugin. However,
>>> this process poses a considerable overhead to the core analysis one may
>>> intend to perform.
>>>
>>
>> I agree it would be useful. Beyond the scope of this series, it would
>> be nice if we could add a control flow related API instead of asking
>> to plugins to do it themselves.
>
> I think there is a balance to be had here. We don't want to
> inadvertently expose QEMU internals to the plugin API. With this series
> at least we rely on stuff the front-end knows which can at least be
> tweaked relatively easily.
>
You're right. Maybe a good way to find the balance is to identify the
real use cases behind this need.
>> If we would provide something like this, is there still a value to add
>> an API to detect interrupt/exceptions/traps events?
>>
>> Note: It's not a critic against what you sent, just an open question
>> on *why* it's useful to access this QEMU implementation related
>> information vs something more generic.
> <snip>
>
> It would be good to have the opinion of the front-end maintainers if
> this is too burdensome or easy enough to manage.
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-21 18:00 ` Pierrick Bouvier
2024-10-21 18:47 ` Alex Bennée
@ 2024-10-21 21:02 ` Julian Ganz
2024-10-21 21:59 ` Pierrick Bouvier
1 sibling, 1 reply; 35+ messages in thread
From: Julian Ganz @ 2024-10-21 21:02 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Pierrick,
October 21, 2024 at 8:00 PM, "Pierrick Bouvier" wrote:
> I agree it would be useful. Beyond the scope of this series, it would be
> nice if we could add a control flow related API instead of asking to
> plugins to do it themselves.
>
> If we would provide something like this, is there still a value to add
> an API to detect interrupt/exceptions/traps events?
>
> Note: It's not a critic against what you sent, just an open question on
> *why* it's useful to access this QEMU implementation related information
> vs something more generic.
The motivation for this API is a plugin that simulates a RISC-V tracing
unit (and produces a trace). For that we actually also needed to
track the "regular" control flow, i.e. find out whether a branch was
taken or where a jump went. That wasn't hard, especially considering
that the TCG API already gives you (more or less) basic blocks. Still,
we ended up tracing every instruction because that made some of the logic
much simpler and easier to reason about.
We realized that we need a trap API because they:
* can occur at any time/point of execusion
* usually come with additional effects such as mode changes.
Helpers for discerning whether an instruction is a jump, a branch
instruction or something else would certainly be helpful if you wanted
cross-platform control flow tracing of some sort, but afaik given such
helpers you would just need to check the last instruction in a
translation block and check where the PC goes after that. Additional
callbacks for specifically this situation strike me as a bit
excessive.
But I could be wrong about that.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-21 21:02 ` Julian Ganz
@ 2024-10-21 21:59 ` Pierrick Bouvier
2024-10-22 8:21 ` Julian Ganz
0 siblings, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-21 21:59 UTC (permalink / raw)
To: Julian Ganz, Julian Ganz, qemu-devel
On 10/21/24 14:02, Julian Ganz wrote:
> Hi, Pierrick,
>
> October 21, 2024 at 8:00 PM, "Pierrick Bouvier" wrote:
>> I agree it would be useful. Beyond the scope of this series, it would be
>> nice if we could add a control flow related API instead of asking to
>> plugins to do it themselves.
>>
>> If we would provide something like this, is there still a value to add
>> an API to detect interrupt/exceptions/traps events?
>>
>> Note: It's not a critic against what you sent, just an open question on
>> *why* it's useful to access this QEMU implementation related information
>> vs something more generic.
>
> The motivation for this API is a plugin that simulates a RISC-V tracing
> unit (and produces a trace). For that we actually also needed to
> track the "regular" control flow, i.e. find out whether a branch was
> taken or where a jump went. That wasn't hard, especially considering
> that the TCG API already gives you (more or less) basic blocks. Still,
> we ended up tracing every instruction because that made some of the logic
> much simpler and easier to reason about.
>
> We realized that we need a trap API because they:
> * can occur at any time/point of execusion
> * usually come with additional effects such as mode changes.
>
Thanks for sharing your insights.
I think there is definitely value in what you offer, and I'm trying to
think how we could extend it in the future easily, without having
another callback when a new event appear. In my experience on plugins,
the least callbacks we have, and the simpler they are, the better it is.
Maybe we could have a single API like:
enum qemu_plugin_cf_event_type {
QEMU_PLUGIN_CF_INTERRUPT;
QEMU_PLUGIN_CF_TRAP;
QEMU_PLUGIN_CF_SEMIHOSTING;
};
/* Sum type, a.k.a. "Rust-like" enum */
typedef struct {
enum qemu_plugin_cf_event_type ev;
union {
data_for_interrupt interrupt;
data_for_trap trap;
data_for_semihosting semihosting;
} qemu_plugin_cf_event;
/* data_for_... could contain things like from/to addresses, interrupt
id, ... */
...
void on_cf_event(qemu_plugin_cf_event ev)
{
switch (ev.type) {
case QEMU_PLUGIN_CF_TRAP:
...
case QEMU_PLUGIN_CF_SEMIHOSTING:
...
default:
g_assert_not_reached();
}
}
/* a plugin can register to one or several event - we could provide a
QEMU_PLUGIN_CF_ALL for plugins tracking all events. */
qemu_plugin_register_cf_cb(QEMU_PLUGIN_CF_TRAP, &on_cf_event);
qemu_plugin_register_cf_cb(QEMU_PLUGIN_CF_SEMIHOSTING, &on_cf_event);
This way, a single callback can be registered for one or several events.
And in the future, we are free to attach more data for every event, and
add other events (TB_FALLTHROUGH, TB_JUMP, etc).
> Helpers for discerning whether an instruction is a jump, a branch
> instruction or something else would certainly be helpful if you wanted
> cross-platform control flow tracing of some sort, but afaik given such
> helpers you would just need to check the last instruction in a
> translation block and check where the PC goes after that. Additional
> callbacks for specifically this situation strike me as a bit
> excessive.
>
> But I could be wrong about that.
>
You're right, and the current cflow plugin is more a demonstration of
using existing API than an efficient solution to this problem.
For cflow detection specifically, I think we can do better, by adding
instrumentation right where we chain/jump between tb, and of course,
tracking other events like you did in this series.
> Regards,
> Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-21 21:59 ` Pierrick Bouvier
@ 2024-10-22 8:21 ` Julian Ganz
2024-10-22 8:58 ` Alex Bennée
2024-10-22 21:15 ` Pierrick Bouvier
0 siblings, 2 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-22 8:21 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Pierrick,
October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
> On 10/21/24 14:02, Julian Ganz wrote:
> > The motivation for this API is a plugin that simulates a RISC-V tracing
> > unit (and produces a trace). For that we actually also needed to
> > track the "regular" control flow, i.e. find out whether a branch was
> > taken or where a jump went. That wasn't hard, especially considering
> > that the TCG API already gives you (more or less) basic blocks. Still,
> > we ended up tracing every instruction because that made some of the logic
> > much simpler and easier to reason about.
> > We realized that we need a trap API because they:
> > * can occur at any time/point of execusion
> > * usually come with additional effects such as mode changes.
> >
> Thanks for sharing your insights.
> I think there is definitely value in what you offer, and I'm trying to think how we could extend it in the future easily, without having another callback when a new event appear. In my experience on plugins, the least callbacks we have, and the simpler they are, the better it is.
>
> Maybe we could have a single API like:
>
> enum qemu_plugin_cf_event_type {
> QEMU_PLUGIN_CF_INTERRUPT;
> QEMU_PLUGIN_CF_TRAP;
> QEMU_PLUGIN_CF_SEMIHOSTING;
> };
I have considered such an enum, as an input for the callback, as a
parameter of the registration function, and both. Of course, if you were
to add a selection parameter for the registration function, you likely
want OR-able flags.
An additional input for the callback type would obviously require a new
function type just for that callback. Since the callbacks are somewhat
similar to the VCPU init, exit, resume, ... ones it felt appropriate
to use the same function type for all of them.
As for the registration, it may make the registration a bit more
convenient and maybe keep the API clutter a bit lower, but not by that
much.
> /* Sum type, a.k.a. "Rust-like" enum */
> typedef struct {
> enum qemu_plugin_cf_event_type ev;
> union {
> data_for_interrupt interrupt;
> data_for_trap trap;
> data_for_semihosting semihosting;
> } qemu_plugin_cf_event;
> /* data_for_... could contain things like from/to addresses, interrupt id, ... */
I don't think this is a good idea.
Traps are just too diverse, imo there is too little overlap between
different architectures, with the sole exception maybe being the PC
prior to the trap. "Interrupt id" sounds like a reasonably common
concept, but then you would need to define a mapping for each and every
architecture. What integer type do you use? In RISC-V, for example,
exceptions and interrupt "ids" are differentiated via the most
significant bit. Dou keep that or do you zero it? And then there's
ring/privilage mode, cause (sometimes for each mode), ...
It would also complicate call sites for hooks in target code. You'd
either need awkwardly long function signitures or setup code for that
struct. Both are things you don't want, as a hook call site should
never distract from the actual logic surrounding them. You could
probably have something reasonable in Rust, using a builder/command
pattern. But in C this would require too much boiler plate code than
I'd be comfortable with.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-22 8:21 ` Julian Ganz
@ 2024-10-22 8:58 ` Alex Bennée
2024-10-22 20:12 ` Julian Ganz
2024-10-22 21:15 ` Pierrick Bouvier
1 sibling, 1 reply; 35+ messages in thread
From: Alex Bennée @ 2024-10-22 8:58 UTC (permalink / raw)
To: Julian Ganz; +Cc: Pierrick Bouvier, Julian Ganz, qemu-devel
"Julian Ganz" <nenut@skiff.uberspace.de> writes:
> Hi, Pierrick,
>
> October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
>> On 10/21/24 14:02, Julian Ganz wrote:
>> > The motivation for this API is a plugin that simulates a RISC-V tracing
>> > unit (and produces a trace). For that we actually also needed to
>> > track the "regular" control flow, i.e. find out whether a branch was
>> > taken or where a jump went. That wasn't hard, especially considering
>> > that the TCG API already gives you (more or less) basic blocks. Still,
>> > we ended up tracing every instruction because that made some of the logic
>> > much simpler and easier to reason about.
>> > We realized that we need a trap API because they:
>> > * can occur at any time/point of execusion
>> > * usually come with additional effects such as mode changes.
>> >
>> Thanks for sharing your insights.
>> I think there is definitely value in what you offer, and I'm trying
>> to think how we could extend it in the future easily, without having
>> another callback when a new event appear. In my experience on
>> plugins, the least callbacks we have, and the simpler they are, the
>> better it is.
>>
>> Maybe we could have a single API like:
>>
<snip>
>
> Traps are just too diverse, imo there is too little overlap between
> different architectures, with the sole exception maybe being the PC
> prior to the trap. "Interrupt id" sounds like a reasonably common
> concept, but then you would need to define a mapping for each and every
> architecture. What integer type do you use? In RISC-V, for example,
> exceptions and interrupt "ids" are differentiated via the most
> significant bit. Dou keep that or do you zero it? And then there's
> ring/privilage mode, cause (sometimes for each mode), ...
>
> It would also complicate call sites for hooks in target code. You'd
> either need awkwardly long function signitures or setup code for that
> struct. Both are things you don't want, as a hook call site should
> never distract from the actual logic surrounding them. You could
> probably have something reasonable in Rust, using a builder/command
> pattern. But in C this would require too much boiler plate code than
> I'd be comfortable with.
How easy would it be to expose a Rust API? I'm curious because now we
are looking to integrate Rust into QEMU we could consider transitioning
to a Rust API for plugins. It has been done before:
https://github.com/novafacing/qemu-rs/tree/main/qemu-plugin-sys
and
https://github.com/novafacing/qemu-rs/tree/main/qemu-plugin
I'm curious as to what it would look like. I don't know how tenable it
would be to run 2 plugin APIs side-by-side long term though. We would
probably want to make a choice. Also how would that affect other C like
APIs like python?
>
> Regards,
> Julian
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-22 8:58 ` Alex Bennée
@ 2024-10-22 20:12 ` Julian Ganz
0 siblings, 0 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-22 20:12 UTC (permalink / raw)
To: Alex Bennée; +Cc: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Alex,
October 22, 2024 at 10:58 AM, "Alex Bennée" wrote:
> How easy would it be to expose a Rust API? I'm curious because now we
> are looking to integrate Rust into QEMU we could consider transitioning
> to a Rust API for plugins. It has been done before:
>
> https://github.com/novafacing/qemu-rs/tree/main/qemu-plugin-sys
>
> and
>
> https://github.com/novafacing/qemu-rs/tree/main/qemu-plugin
>
> I'm curious as to what it would look like. I don't know how tenable it
> would be to run 2 plugin APIs side-by-side long term though. We would
> probably want to make a choice. Also how would that affect other C like
> APIs like python?
I'm maybe not an expert w.r.t. plugins with Rust, but here are my
thoughts:
Calling C code from Rust is obviously not an issue. For ideomatic Rust
(not littered with "unsafe") you want an abstraction over that, but as
Qemu is C you need that somewhere anyway.
Things that are generally easy to handle are opaque types behind
pointers (this is probably true for most language binding) and C
strings, as long as you can figure out who owns them and how long they
live. Things in the current API which make things a bit awkward are
(probably) unions and Glib-types such as the GArray returned by
qemu_plugin_get_registers. Also, you can use Rust functions for
callbacks, but ideally you want to allow using all types implementing
the Fn trait, e.g. closures carrying some context. For that, you need to
transport that context from the point of registration to the callback,
i.e. you need some udata. Not all callbacks have udata, but looking
closer the ones lacking it are those you register only once, which means
we could have some "static" storage for those context. It's not ideal,
but not a show-stopper either. I didn't check how the qemu-plugin crate
handles that situation.
With a native Rust interface, you would not have those problems.
However, for plugins you would need a dylib interface, which comes with
restrictions. In particular, you cannot use generics in the interface.
To allow for the very extension we want the interface would make heavy
use of Box<dyn SomeTrait>, in particular Box<dyn Fn(...) -> ...>.
The awkward thing about those is that you cannot simply convert them
into a void pointer because the "dyn" means fat pointers are involved:
unlike in C++, the vtable is embedded in the "pointer". Since we want to
invoke those from the C side, we need another level of indirection which
lets us operate on an opaque Rust type through non-generic functions
that then does the thing we want to the boxed thing. Ironically, you
don't have the same problem with a Rust plugin developed against a C
interface because you can just use a generic function unpacking (i.e.
casting) the context and throw its instantiation's pointer over the
fence.
So... I'm not sure about the benefits of a native Rust plugin API
compared to the qemu-plugin crate or something similar. Especially
considering that we would want to use the very same callback registry in
the back, anyway. That is, if you want feature parity between the
different plugin APIs.
There are some things that would make language bindings easier in
general, but some of those would involve breaking changes and may not
be worth it.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-22 8:21 ` Julian Ganz
2024-10-22 8:58 ` Alex Bennée
@ 2024-10-22 21:15 ` Pierrick Bouvier
2024-10-23 12:56 ` Julian Ganz
1 sibling, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-22 21:15 UTC (permalink / raw)
To: Julian Ganz, Julian Ganz, qemu-devel
On 10/22/24 01:21, Julian Ganz wrote:
> Hi, Pierrick,
>
> October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
>> On 10/21/24 14:02, Julian Ganz wrote:
>>> The motivation for this API is a plugin that simulates a RISC-V tracing
>>> unit (and produces a trace). For that we actually also needed to
>>> track the "regular" control flow, i.e. find out whether a branch was
>>> taken or where a jump went. That wasn't hard, especially considering
>>> that the TCG API already gives you (more or less) basic blocks. Still,
>>> we ended up tracing every instruction because that made some of the logic
>>> much simpler and easier to reason about.
>>> We realized that we need a trap API because they:
>>> * can occur at any time/point of execusion
>>> * usually come with additional effects such as mode changes.
>>>
>> Thanks for sharing your insights.
>> I think there is definitely value in what you offer, and I'm trying to think how we could extend it in the future easily, without having another callback when a new event appear. In my experience on plugins, the least callbacks we have, and the simpler they are, the better it is.
>>
>> Maybe we could have a single API like:
>>
>> enum qemu_plugin_cf_event_type {
>> QEMU_PLUGIN_CF_INTERRUPT;
>> QEMU_PLUGIN_CF_TRAP;
>> QEMU_PLUGIN_CF_SEMIHOSTING;
>> };
>
> I have considered such an enum, as an input for the callback, as a
> parameter of the registration function, and both. Of course, if you were
> to add a selection parameter for the registration function, you likely
> want OR-able flags.
>
> An additional input for the callback type would obviously require a new
> function type just for that callback. Since the callbacks are somewhat
> similar to the VCPU init, exit, resume, ... ones it felt appropriate
> to use the same function type for all of them.
>
I tend to disagree on that. IMHO, it's better to reduce number of API
entries instead of callback types.
It's easy for a user to understand how to implement a given callback,
while it's hard to understand which API you need for which thing.
For the syscall cbs, we already have a specific callback. So why not here?
I tend to see init/exit/resume events as different because you can't get
useful information attached, except the cpu id. But for control flow
related stuff, you can be interested in having more.
I understand you're focused on those "events" for now, but while digging
into this, it seems like the initial need was to track the control flow.
So I would like to push more in this direction, and offer a more
extendable solution. Do you think the end goal for a plugin using this
information may be different? (beyond a plugin counting
trap/interrupts/semihosting event).
> As for the registration, it may make the registration a bit more
> convenient and maybe keep the API clutter a bit lower, but not by that
> much.
>
It's ok for the user. But I think it's more complicated to extend, when
we'll want to introduce control flow API in the future. Do we want 5 or
6 different callbacks when people want to track fully control flow from
a plugin?
>
>> /* Sum type, a.k.a. "Rust-like" enum */
>> typedef struct {
>> enum qemu_plugin_cf_event_type ev;
>> union {
>> data_for_interrupt interrupt;
>> data_for_trap trap;
>> data_for_semihosting semihosting;
>> } qemu_plugin_cf_event;
>> /* data_for_... could contain things like from/to addresses, interrupt id, ... */
>
> I don't think this is a good idea.
>
> Traps are just too diverse, imo there is too little overlap between
> different architectures, with the sole exception maybe being the PC
> prior to the trap. "Interrupt id" sounds like a reasonably common
> concept, but then you would need to define a mapping for each and every
> architecture. What integer type do you use? In RISC-V, for example,
> exceptions and interrupt "ids" are differentiated via the most
> significant bit. Dou keep that or do you zero it? And then there's
> ring/privilage mode, cause (sometimes for each mode), ...
>
I didn't want to open the per architecture pandora box :).
I don't think the plugin API itself should deal with per architecture
details like meaning of a given id. I was just thinking to push this
"raw" information to the plugin, that may/may not use architecture
specific knowledge to do its work. We already have plugins that have
similar per architecture knowledge (contrib/plugins/howvec.c) and it's
ok in some specific cases.
But having something like from/to address seems useful to start. Even if
we don't provide it for all events yet, it's ok.
> It would also complicate call sites for hooks in target code. You'd
> either need awkwardly long function signitures or setup code for that
> struct. Both are things you don't want, as a hook call site should
> never distract from the actual logic surrounding them. You could
> probably have something reasonable in Rust, using a builder/command
> pattern. But in C this would require too much boiler plate code than
> I'd be comfortable with.
>
We can have one "builder" function per data type, with fixed parameters
(no varargs), it's reasonable and would scale well with new entries/data
information.
> Regards,
> Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-22 21:15 ` Pierrick Bouvier
@ 2024-10-23 12:56 ` Julian Ganz
2024-10-23 13:57 ` Alex Bennée
2024-10-23 15:16 ` Pierrick Bouvier
0 siblings, 2 replies; 35+ messages in thread
From: Julian Ganz @ 2024-10-23 12:56 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Pierrick,
resent as I was too stupid to hit reply instead of reply-all.
October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
>
> On 10/22/24 01:21, Julian Ganz wrote:
>
> >
> > Hi, Pierrick,
> > October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
> >
> > >
> > > Maybe we could have a single API like:
> > >
> > > enum qemu_plugin_cf_event_type {
> > > QEMU_PLUGIN_CF_INTERRUPT;
> > > QEMU_PLUGIN_CF_TRAP;
> > > QEMU_PLUGIN_CF_SEMIHOSTING;
> > > };
> > >
> > I have considered such an enum, as an input for the callback, as a
> > parameter of the registration function, and both. Of course, if you were
> > to add a selection parameter for the registration function, you likely
> > want OR-able flags.
> > An additional input for the callback type would obviously require a new
> > function type just for that callback. Since the callbacks are somewhat
> > similar to the VCPU init, exit, resume, ... ones it felt appropriate
> > to use the same function type for all of them.
> >
> I tend to disagree on that. IMHO, it's better to reduce number of API entries instead of callback types.
> It's easy for a user to understand how to implement a given callback, while it's hard to understand which API you need for which thing.
>
> For the syscall cbs, we already have a specific callback. So why not here?
<snip>
> > As for the registration, it may make the registration a bit more
> > convenient and maybe keep the API clutter a bit lower, but not by that
> > much.
> >
> It's ok for the user. But I think it's more complicated to extend, when we'll want to introduce control flow API in the future. Do we want 5 or 6 different callbacks when people want to track fully control flow from a plugin?
Ok, I'll introduce an enum and combine the three callbacks in the next
iteration then.
> > > typedef struct {
> > > enum qemu_plugin_cf_event_type ev;
> > > union {
> > > data_for_interrupt interrupt;
> > > data_for_trap trap;
> > > data_for_semihosting semihosting;
> > > } qemu_plugin_cf_event;
> > > /* data_for_... could contain things like from/to addresses, interrupt id, ... */
> > >
> > I don't think this is a good idea.
> > Traps are just too diverse, imo there is too little overlap between
> > different architectures, with the sole exception maybe being the PC
> > prior to the trap. "Interrupt id" sounds like a reasonably common
> > concept, but then you would need to define a mapping for each and every
> > architecture. What integer type do you use? In RISC-V, for example,
> > exceptions and interrupt "ids" are differentiated via the most
> > significant bit. Dou keep that or do you zero it? And then there's
> > ring/privilage mode, cause (sometimes for each mode), ...
> >
> I didn't want to open the per architecture pandora box :).
> I don't think the plugin API itself should deal with per architecture
> details like meaning of a given id. I was just thinking to push this "raw" information to the plugin, that may/may not use architecture specific knowledge to do its work. We already have plugins that have similar per architecture knowledge (contrib/plugins/howvec.c) and it's ok in some specific cases.
But how would such an interface look? The last PC aside, what would you
include, and how? A GArray with named items that are itself just opaque
blobs?
And what would be the benefit compared to just querying the respective
target specific registers through qemu_plugin_read_register? Which btw.
is what we were going to do for our use-case. Even the example you
brought up (howvec) uses querying functions and doesn't expect to get
all the info via parameters.
> But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
Yes, I certainly see the advantages of having either the last PC or the
would-be-next PC as they are sufficiently universal. You can usually
retrieve them from target-specific registers, but that may be more
complicated in practice. In the case of RISC-V for example, the value
of the EPC differs between interrupts and exceptions.
That PC value should also be easy enough to obtain at the hook call
sites. We only need to store the (old) PC before doing the setup. The
"to-address" is the current PC at the time the callback is invoked.
Anything else would be a bug. I was going to write that you can
already query that in a plugin through a dedicated helper function
but apparently I misremembered.
I'll include this in the next iteration.
> > It would also complicate call sites for hooks in target code. You'd
> > either need awkwardly long function signitures or setup code for that
> > struct. Both are things you don't want, as a hook call site should
> > never distract from the actual logic surrounding them. You could
> > probably have something reasonable in Rust, using a builder/command
> > pattern. But in C this would require too much boiler plate code than
> > I'd be comfortable with.
> >
> We can have one "builder" function per data type, with fixed parameters (no varargs), it's reasonable and would scale well with new entries/data information.
I'm still not on board on preparing a more complex data type. For the
next iteration I'd rather stick to a simple function receiving the
"type" of event and the PCs. That may not be extensible, but I don't see
any benefit in shoehorning inheritelntly target-specifc information into
a complex struct.
If this is a hard requirement, I'll of course still do so.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 12:56 ` Julian Ganz
@ 2024-10-23 13:57 ` Alex Bennée
2024-10-23 15:21 ` Pierrick Bouvier
2024-10-23 15:16 ` Pierrick Bouvier
1 sibling, 1 reply; 35+ messages in thread
From: Alex Bennée @ 2024-10-23 13:57 UTC (permalink / raw)
To: Julian Ganz; +Cc: Pierrick Bouvier, Julian Ganz, qemu-devel
"Julian Ganz" <nenut@skiff.uberspace.de> writes:
> Hi, Pierrick,
>
> resent as I was too stupid to hit reply instead of reply-all.
>
> October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
>>
>> On 10/22/24 01:21, Julian Ganz wrote:
>>
>> >
>> > Hi, Pierrick,
>> > October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
>> >
<snip>
>> > I don't think this is a good idea.
>> > Traps are just too diverse, imo there is too little overlap between
>> > different architectures, with the sole exception maybe being the PC
>> > prior to the trap. "Interrupt id" sounds like a reasonably common
>> > concept, but then you would need to define a mapping for each and every
>> > architecture. What integer type do you use? In RISC-V, for example,
>> > exceptions and interrupt "ids" are differentiated via the most
>> > significant bit. Dou keep that or do you zero it? And then there's
>> > ring/privilage mode, cause (sometimes for each mode), ...
>> >
>> I didn't want to open the per architecture pandora box :).
>> I don't think the plugin API itself should deal with per architecture
>> details like meaning of a given id. I was just thinking to push this
>> "raw" information to the plugin, that may/may not use architecture
>> specific knowledge to do its work. We already have plugins that have
>> similar per architecture knowledge (contrib/plugins/howvec.c) and
>> it's ok in some specific cases.
>
> But how would such an interface look? The last PC aside, what would you
> include, and how? A GArray with named items that are itself just opaque
> blobs?
>
> And what would be the benefit compared to just querying the respective
> target specific registers through qemu_plugin_read_register? Which btw.
> is what we were going to do for our use-case. Even the example you
> brought up (howvec) uses querying functions and doesn't expect to get
> all the info via parameters.
I think the register access probably provides everything you need. Some
targets provide a wider access than other though. I haven't looked at
the Risc V code but certainly the Arm code exposes pretty much all
system registers to the gdbstub (and hence the plugin interface).
If there is example of state that isn't accessible this way then I'd
like to know it.
>> But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
>
> Yes, I certainly see the advantages of having either the last PC or the
> would-be-next PC as they are sufficiently universal. You can usually
> retrieve them from target-specific registers, but that may be more
> complicated in practice. In the case of RISC-V for example, the value
> of the EPC differs between interrupts and exceptions.
>
> That PC value should also be easy enough to obtain at the hook call
> sites. We only need to store the (old) PC before doing the setup. The
> "to-address" is the current PC at the time the callback is invoked.
> Anything else would be a bug. I was going to write that you can
> already query that in a plugin through a dedicated helper function
> but apparently I misremembered.
>
> I'll include this in the next iteration.
There are some dragons with pc/npc as each front-end deals with it its
own way and some targets have delay slots which makes things even
messier.
>
>> > It would also complicate call sites for hooks in target code. You'd
>> > either need awkwardly long function signitures or setup code for that
>> > struct. Both are things you don't want, as a hook call site should
>> > never distract from the actual logic surrounding them. You could
>> > probably have something reasonable in Rust, using a builder/command
>> > pattern. But in C this would require too much boiler plate code than
>> > I'd be comfortable with.
>> >
>> We can have one "builder" function per data type, with fixed parameters (no varargs), it's reasonable and would scale well with new entries/data information.
>
> I'm still not on board on preparing a more complex data type. For the
> next iteration I'd rather stick to a simple function receiving the
> "type" of event and the PCs. That may not be extensible, but I don't see
> any benefit in shoehorning inheritelntly target-specifc information into
> a complex struct.
>
> If this is a hard requirement, I'll of course still do so.
No lets keep it simple for the first iteration. We can also expand the
API later and bump the API versions as appropriate.
>
> Regards,
> Julian
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 13:57 ` Alex Bennée
@ 2024-10-23 15:21 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-23 15:21 UTC (permalink / raw)
To: Alex Bennée, Julian Ganz; +Cc: Julian Ganz, qemu-devel
On 10/23/24 06:57, Alex Bennée wrote:
> "Julian Ganz" <nenut@skiff.uberspace.de> writes:
>
>> Hi, Pierrick,
>>
>> resent as I was too stupid to hit reply instead of reply-all.
>>
>> October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
>>>
>>> On 10/22/24 01:21, Julian Ganz wrote:
>>>
>>>>
>>>> Hi, Pierrick,
>>>> October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
>>>>
> <snip>
>>>> I don't think this is a good idea.
>>>> Traps are just too diverse, imo there is too little overlap between
>>>> different architectures, with the sole exception maybe being the PC
>>>> prior to the trap. "Interrupt id" sounds like a reasonably common
>>>> concept, but then you would need to define a mapping for each and every
>>>> architecture. What integer type do you use? In RISC-V, for example,
>>>> exceptions and interrupt "ids" are differentiated via the most
>>>> significant bit. Dou keep that or do you zero it? And then there's
>>>> ring/privilage mode, cause (sometimes for each mode), ...
>>>>
>>> I didn't want to open the per architecture pandora box :).
>>> I don't think the plugin API itself should deal with per architecture
>>> details like meaning of a given id. I was just thinking to push this
>>> "raw" information to the plugin, that may/may not use architecture
>>> specific knowledge to do its work. We already have plugins that have
>>> similar per architecture knowledge (contrib/plugins/howvec.c) and
>>> it's ok in some specific cases.
>>
>> But how would such an interface look? The last PC aside, what would you
>> include, and how? A GArray with named items that are itself just opaque
>> blobs?
>>
>> And what would be the benefit compared to just querying the respective
>> target specific registers through qemu_plugin_read_register? Which btw.
>> is what we were going to do for our use-case. Even the example you
>> brought up (howvec) uses querying functions and doesn't expect to get
>> all the info via parameters.
>
> I think the register access probably provides everything you need. Some
> targets provide a wider access than other though. I haven't looked at
> the Risc V code but certainly the Arm code exposes pretty much all
> system registers to the gdbstub (and hence the plugin interface).
>
> If there is example of state that isn't accessible this way then I'd
> like to know it.
>
>>> But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
>>
>> Yes, I certainly see the advantages of having either the last PC or the
>> would-be-next PC as they are sufficiently universal. You can usually
>> retrieve them from target-specific registers, but that may be more
>> complicated in practice. In the case of RISC-V for example, the value
>> of the EPC differs between interrupts and exceptions.
>>
>> That PC value should also be easy enough to obtain at the hook call
>> sites. We only need to store the (old) PC before doing the setup. The
>> "to-address" is the current PC at the time the callback is invoked.
>> Anything else would be a bug. I was going to write that you can
>> already query that in a plugin through a dedicated helper function
>> but apparently I misremembered.
>>
>> I'll include this in the next iteration.
>
> There are some dragons with pc/npc as each front-end deals with it its
> own way and some targets have delay slots which makes things even
> messier.
>
Yes, if it gets too complicated for current series, we can just have the
event passed to the callback, and no more information.
As pointed in my previous message, I just want to avoid the multiple
callbacks route for this specific area. It's fine if we don't have any
attached data for now.
>>
>>>> It would also complicate call sites for hooks in target code. You'd
>>>> either need awkwardly long function signitures or setup code for that
>>>> struct. Both are things you don't want, as a hook call site should
>>>> never distract from the actual logic surrounding them. You could
>>>> probably have something reasonable in Rust, using a builder/command
>>>> pattern. But in C this would require too much boiler plate code than
>>>> I'd be comfortable with.
>>>>
>>> We can have one "builder" function per data type, with fixed parameters (no varargs), it's reasonable and would scale well with new entries/data information.
>>
>> I'm still not on board on preparing a more complex data type. For the
>> next iteration I'd rather stick to a simple function receiving the
>> "type" of event and the PCs. That may not be extensible, but I don't see
>> any benefit in shoehorning inheritelntly target-specifc information into
>> a complex struct.
>>
>> If this is a hard requirement, I'll of course still do so.
>
> No lets keep it simple for the first iteration. We can also expand the
> API later and bump the API versions as appropriate.
>
The type of event, eventually with pcs if you can get them is already
satisfying, and simple enough.
>>
>> Regards,
>> Julian
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 12:56 ` Julian Ganz
2024-10-23 13:57 ` Alex Bennée
@ 2024-10-23 15:16 ` Pierrick Bouvier
2024-10-23 16:12 ` Julian Ganz
1 sibling, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-23 15:16 UTC (permalink / raw)
To: Julian Ganz, Julian Ganz, qemu-devel
Hi Julian,
On 10/23/24 05:56, Julian Ganz wrote:
> Hi, Pierrick,
>
> resent as I was too stupid to hit reply instead of reply-all.
>
> October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
>>
>> On 10/22/24 01:21, Julian Ganz wrote:
>>
>>>
>>> Hi, Pierrick,
>>> October 21, 2024 at 11:59 PM, "Pierrick Bouvier" wrote:
>>>
>>>>
>>>> Maybe we could have a single API like:
>>>>
>>>> enum qemu_plugin_cf_event_type {
>>>> QEMU_PLUGIN_CF_INTERRUPT;
>>>> QEMU_PLUGIN_CF_TRAP;
>>>> QEMU_PLUGIN_CF_SEMIHOSTING;
>>>> };
>>>>
>>> I have considered such an enum, as an input for the callback, as a
>>> parameter of the registration function, and both. Of course, if you were
>>> to add a selection parameter for the registration function, you likely
>>> want OR-able flags.
>>> An additional input for the callback type would obviously require a new
>>> function type just for that callback. Since the callbacks are somewhat
>>> similar to the VCPU init, exit, resume, ... ones it felt appropriate
>>> to use the same function type for all of them.
>>>
>> I tend to disagree on that. IMHO, it's better to reduce number of API entries instead of callback types.
>> It's easy for a user to understand how to implement a given callback, while it's hard to understand which API you need for which thing.
>>
>> For the syscall cbs, we already have a specific callback. So why not here?
>
> <snip>
>
>>> As for the registration, it may make the registration a bit more
>>> convenient and maybe keep the API clutter a bit lower, but not by that
>>> much.
>>>
>> It's ok for the user. But I think it's more complicated to extend, when we'll want to introduce control flow API in the future. Do we want 5 or 6 different callbacks when people want to track fully control flow from a plugin?
>
> Ok, I'll introduce an enum and combine the three callbacks in the next
> iteration then.
>
>>>> typedef struct {
>>>> enum qemu_plugin_cf_event_type ev;
>>>> union {
>>>> data_for_interrupt interrupt;
>>>> data_for_trap trap;
>>>> data_for_semihosting semihosting;
>>>> } qemu_plugin_cf_event;
>>>> /* data_for_... could contain things like from/to addresses, interrupt id, ... */
>>>>
>>> I don't think this is a good idea.
>>> Traps are just too diverse, imo there is too little overlap between
>>> different architectures, with the sole exception maybe being the PC
>>> prior to the trap. "Interrupt id" sounds like a reasonably common
>>> concept, but then you would need to define a mapping for each and every
>>> architecture. What integer type do you use? In RISC-V, for example,
>>> exceptions and interrupt "ids" are differentiated via the most
>>> significant bit. Dou keep that or do you zero it? And then there's
>>> ring/privilage mode, cause (sometimes for each mode), ...
>>>
>> I didn't want to open the per architecture pandora box :).
>> I don't think the plugin API itself should deal with per architecture
>> details like meaning of a given id. I was just thinking to push this "raw" information to the plugin, that may/may not use architecture specific knowledge to do its work. We already have plugins that have similar per architecture knowledge (contrib/plugins/howvec.c) and it's ok in some specific cases.
>
> But how would such an interface look? The last PC aside, what would you
> include, and how? A GArray with named items that are itself just opaque
> blobs?
>
I was not thinking about a new interface for this. Having the "raw"
interrupt id is enough for a plugin to do useful things, by having
knowledge of which architecture it's instrumenting.
> And what would be the benefit compared to just querying the respective
> target specific registers through qemu_plugin_read_register? Which btw.
> is what we were going to do for our use-case. Even the example you
> brought up (howvec) uses querying functions and doesn't expect to get
> all the info via parameters.
>
You're right, but it's because it's querying instruction data.
I may be wrong on that, but at translation time, we may or may not be
interested in accessing tb/insn data.
However, for control flow analysis, beyond a simple counting plugin, we
probably want to access further data almost everytime.
I see it closer from syscall instrumentation, which pushes the syscall
id, and all register values, instead of letting the user poke it. Makes
more sense compared to that?
>> But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
>
> Yes, I certainly see the advantages of having either the last PC or the
> would-be-next PC as they are sufficiently universal. You can usually
> retrieve them from target-specific registers, but that may be more
> complicated in practice. In the case of RISC-V for example, the value
> of the EPC differs between interrupts and exceptions.
>
To the opposite of interrupt id, a PC is something universal by
definition, and with a single meaning across architecture. However,
accessing it by name varies per architecture, and even per sub events,
as you are stating for RISC-V.
> That PC value should also be easy enough to obtain at the hook call
> sites. We only need to store the (old) PC before doing the setup. The
> "to-address" is the current PC at the time the callback is invoked.
> Anything else would be a bug. I was going to write that you can
> already query that in a plugin through a dedicated helper function
> but apparently I misremembered.
>
> I'll include this in the next iteration.
>
>>> It would also complicate call sites for hooks in target code. You'd
>>> either need awkwardly long function signitures or setup code for that
>>> struct. Both are things you don't want, as a hook call site should
>>> never distract from the actual logic surrounding them. You could
>>> probably have something reasonable in Rust, using a builder/command
>>> pattern. But in C this would require too much boiler plate code than
>>> I'd be comfortable with.
>>>
>> We can have one "builder" function per data type, with fixed parameters (no varargs), it's reasonable and would scale well with new entries/data information.
>
> I'm still not on board on preparing a more complex data type. For the
> next iteration I'd rather stick to a simple function receiving the
> "type" of event and the PCs. That may not be extensible, but I don't see
> any benefit in shoehorning inheritelntly target-specifc information into
> a complex struct.
>
It's a good compromise for now, and avoid introducing a more complex
data type.
> If this is a hard requirement, I'll of course still do so.
>
My goal was not to hijack this series, or put the burden on you, but to
talk about which direction we want to go.
As long as we start with a single callback (vs one per event), I'm fine
to go slowly and iterate in the future.
> Regards,
> Julian
Thanks Julian!
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 15:16 ` Pierrick Bouvier
@ 2024-10-23 16:12 ` Julian Ganz
2024-10-23 16:39 ` Pierrick Bouvier
0 siblings, 1 reply; 35+ messages in thread
From: Julian Ganz @ 2024-10-23 16:12 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Pierrick,
October 23, 2024 at 5:16 PM, "Pierrick Bouvier" wrote:
>
> Hi Julian,
>
> On 10/23/24 05:56, Julian Ganz wrote:
>
> > October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
> >
> > >
> > > On 10/22/24 01:21, Julian Ganz wrote:
> > >
> >
> > Ok, I'll introduce an enum and combine the three callbacks in the next
> > iteration then.
> > typedef struct {
> > enum qemu_plugin_cf_event_type ev;
> > union {
> > data_for_interrupt interrupt;
> > data_for_trap trap;
> > data_for_semihosting semihosting;
> > } qemu_plugin_cf_event;
> > /* data_for_... could contain things like from/to addresses, interrupt id, ... */
> >
> > I don't think this is a good idea.
> > Traps are just too diverse, imo there is too little overlap between
> > different architectures, with the sole exception maybe being the PC
> > prior to the trap. "Interrupt id" sounds like a reasonably common
> > concept, but then you would need to define a mapping for each and every
> > architecture. What integer type do you use? In RISC-V, for example,
> > exceptions and interrupt "ids" are differentiated via the most
> > significant bit. Dou keep that or do you zero it? And then there's
> > ring/privilage mode, cause (sometimes for each mode), ...
> >
> > >
> > > I didn't want to open the per architecture pandora box :).
> > > I don't think the plugin API itself should deal with per architecture
> > > details like meaning of a given id. I was just thinking to push this "raw" information to the plugin, that may/may not use architecture specific knowledge to do its work. We already have plugins that have similar per architecture knowledge (contrib/plugins/howvec.c) and it's ok in some specific cases.
> > >
> > But how would such an interface look? The last PC aside, what would you
> > include, and how? A GArray with named items that are itself just opaque
> > blobs?
> >
> I was not thinking about a new interface for this. Having the "raw" interrupt id is enough for a plugin to do useful things, by having knowledge of which architecture it's instrumenting.
But what is would the "raw" interrupt id even be for a given
architecture? I don't think you can answer this question with "obviously
this _one_ integer" for all of them.
> >
> > And what would be the benefit compared to just querying the respective
> > target specific registers through qemu_plugin_read_register? Which btw.
> > is what we were going to do for our use-case. Even the example you
> > brought up (howvec) uses querying functions and doesn't expect to get
> > all the info via parameters.
> >
> You're right, but it's because it's querying instruction data.
> I may be wrong on that, but at translation time, we may or may not be interested in accessing tb/insn data.
>
> However, for control flow analysis, beyond a simple counting plugin, we probably want to access further data almost everytime.
>
> I see it closer from syscall instrumentation, which pushes the syscall id, and all register values, instead of letting the user poke it. Makes more sense compared to that?
Yes, but then you are in "GArray of named, potentially complex value"
terretory again. And the comparison with syscalls also falls apart when
you consider that, for syscalls, they are well defined and enumerated
identically for at least a variety of targets, while the same kind of
"enumeration", if it even exists, is in completely different order for
every architecture.
> >
> > >
> > > But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
> > >
> > Yes, I certainly see the advantages of having either the last PC or the
> > would-be-next PC as they are sufficiently universal. You can usually
> > retrieve them from target-specific registers, but that may be more
> > complicated in practice. In the case of RISC-V for example, the value
> > of the EPC differs between interrupts and exceptions.
> >
> To the opposite of interrupt id, a PC is something universal by definition, and with a single meaning across architecture. However, accessing it by name varies per architecture, and even per sub events, as you are stating for RISC-V.
Yes. And for that very reason I would not pass "the EPC" to a callback
but a clearly, target agnostic, defined value such as:
| The PC of the instruction that would have been executed next, were it
| not for that event
or
| The PC of the instruction that was executed befroe the event occurred
And unlike interrupt ids, the plugin API already has a precedent for
what type to use: uint64_t
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 16:12 ` Julian Ganz
@ 2024-10-23 16:39 ` Pierrick Bouvier
2024-10-23 17:12 ` Julian Ganz
0 siblings, 1 reply; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-23 16:39 UTC (permalink / raw)
To: Julian Ganz, Julian Ganz, qemu-devel
On 10/23/24 09:12, Julian Ganz wrote:
> Hi, Pierrick,
>
> October 23, 2024 at 5:16 PM, "Pierrick Bouvier" wrote:
>>
>> Hi Julian,
>>
>> On 10/23/24 05:56, Julian Ganz wrote:
>>
>>> October 22, 2024 at 11:15 PM, "Pierrick Bouvier" wrote:
>>>
>>>>
>>>> On 10/22/24 01:21, Julian Ganz wrote:
>>>>
>>>
>>> Ok, I'll introduce an enum and combine the three callbacks in the next
>>> iteration then.
>>> typedef struct {
>>> enum qemu_plugin_cf_event_type ev;
>>> union {
>>> data_for_interrupt interrupt;
>>> data_for_trap trap;
>>> data_for_semihosting semihosting;
>>> } qemu_plugin_cf_event;
>>> /* data_for_... could contain things like from/to addresses, interrupt id, ... */
>>>
>>> I don't think this is a good idea.
>>> Traps are just too diverse, imo there is too little overlap between
>>> different architectures, with the sole exception maybe being the PC
>>> prior to the trap. "Interrupt id" sounds like a reasonably common
>>> concept, but then you would need to define a mapping for each and every
>>> architecture. What integer type do you use? In RISC-V, for example,
>>> exceptions and interrupt "ids" are differentiated via the most
>>> significant bit. Dou keep that or do you zero it? And then there's
>>> ring/privilage mode, cause (sometimes for each mode), ...
>>>
>>>>
>>>> I didn't want to open the per architecture pandora box :).
>>>> I don't think the plugin API itself should deal with per architecture
>>>> details like meaning of a given id. I was just thinking to push this "raw" information to the plugin, that may/may not use architecture specific knowledge to do its work. We already have plugins that have similar per architecture knowledge (contrib/plugins/howvec.c) and it's ok in some specific cases.
>>>>
>>> But how would such an interface look? The last PC aside, what would you
>>> include, and how? A GArray with named items that are itself just opaque
>>> blobs?
>>>
>> I was not thinking about a new interface for this. Having the "raw" interrupt id is enough for a plugin to do useful things, by having knowledge of which architecture it's instrumenting.
>
> But what is would the "raw" interrupt id even be for a given
> architecture? I don't think you can answer this question with "obviously
> this _one_ integer" for all of them.
>
Choosing interrupt id as an example of what we want to include was
confusing, and brought more conversation than I expected.
I wanted to point that we may want different data per event, instead of
talking specifically of interrupt or per architecture specific data.
To still answer you, I was thinking sharing interrupt number for x86_64,
or interrupt id for aarch64. It's probably too naive, so let's drop this
and move on :).
>>>
>>> And what would be the benefit compared to just querying the respective
>>> target specific registers through qemu_plugin_read_register? Which btw.
>>> is what we were going to do for our use-case. Even the example you
>>> brought up (howvec) uses querying functions and doesn't expect to get
>>> all the info via parameters.
>>>
>> You're right, but it's because it's querying instruction data.
>> I may be wrong on that, but at translation time, we may or may not be interested in accessing tb/insn data.
>>
>> However, for control flow analysis, beyond a simple counting plugin, we probably want to access further data almost everytime.
>>
>> I see it closer from syscall instrumentation, which pushes the syscall id, and all register values, instead of letting the user poke it. Makes more sense compared to that?
>
> Yes, but then you are in "GArray of named, potentially complex value"
> terretory again. And the comparison with syscalls also falls apart when
> you consider that, for syscalls, they are well defined and enumerated
> identically for at least a variety of targets, while the same kind of
> "enumeration", if it even exists, is in completely different order for
> every architecture.
>
We can restrict to having from/to PCs for now. Mentioning interrupt id
as example was a mistake.
>>>
>>>>
>>>> But having something like from/to address seems useful to start. Even if we don't provide it for all events yet, it's ok.
>>>>
>>> Yes, I certainly see the advantages of having either the last PC or the
>>> would-be-next PC as they are sufficiently universal. You can usually
>>> retrieve them from target-specific registers, but that may be more
>>> complicated in practice. In the case of RISC-V for example, the value
>>> of the EPC differs between interrupts and exceptions.
>>>
>> To the opposite of interrupt id, a PC is something universal by definition, and with a single meaning across architecture. However, accessing it by name varies per architecture, and even per sub events, as you are stating for RISC-V.
>
> Yes. And for that very reason I would not pass "the EPC" to a callback
> but a clearly, target agnostic, defined value such as:
>
> | The PC of the instruction that would have been executed next, were it
> | not for that event
>
> or
>
> | The PC of the instruction that was executed befroe the event occurred
>
> And unlike interrupt ids, the plugin API already has a precedent for
> what type to use: uint64_t
>
Looks good. As said in previous message, we can drop the complex data
type idea.
So we could have something like:
/* plugin side */
void on_cf_event(qemu_plugin_cf_event_type, uint64_t from, uint64_t to) {
...
}
/* API side */
void qemu_plugin_register_vcpu_syscall_cb(
qemu_plugin_id_t id, qemu_plugin_cf_event_type type,
qemu_plugin_register_vcpu_cf_cb);
We thus would have a new callback type qemu_plugin_vcpu_cf_cb_t added.
For registering several events, we might define enum values for types
indexed on every bit, so we can directly xor the enum to register
several types. (same idea than existing qemu_plugin_mem_rw, but for more
values, with a specific ALL value covering all possibilities).
Does that match what you were thinking?
> Regards,
> Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 16:39 ` Pierrick Bouvier
@ 2024-10-23 17:12 ` Julian Ganz
2024-10-23 17:53 ` Pierrick Bouvier
0 siblings, 1 reply; 35+ messages in thread
From: Julian Ganz @ 2024-10-23 17:12 UTC (permalink / raw)
To: Pierrick Bouvier, Julian Ganz, qemu-devel
Hi, Pierrick,
October 23, 2024 at 6:39 PM, "Pierrick Bouvier" wrote:
>
> So we could have something like:
>
> /* plugin side */
> void on_cf_event(qemu_plugin_cf_event_type, uint64_t from, uint64_t to) {
> ...
> }
We also need the VCPU id, but yes.
> /* API side */
> void qemu_plugin_register_vcpu_syscall_cb(
> qemu_plugin_id_t id, qemu_plugin_cf_event_type type, qemu_plugin_register_vcpu_cf_cb);
>
> We thus would have a new callback type qemu_plugin_vcpu_cf_cb_t added.
>
> For registering several events, we might define enum values for types indexed on every bit, so we can directly xor the enum to register several types. (same idea than existing qemu_plugin_mem_rw, but for more values, with a specific ALL value covering all possibilities).
>
> Does that match what you were thinking?
Yes.
Regards,
Julian
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [RFC PATCH v2 0/7] tcg-plugins: add hooks for interrupts, exceptions and traps
2024-10-23 17:12 ` Julian Ganz
@ 2024-10-23 17:53 ` Pierrick Bouvier
0 siblings, 0 replies; 35+ messages in thread
From: Pierrick Bouvier @ 2024-10-23 17:53 UTC (permalink / raw)
To: Julian Ganz, Julian Ganz, qemu-devel
On 10/23/24 10:12, Julian Ganz wrote:
> Hi, Pierrick,
>
> October 23, 2024 at 6:39 PM, "Pierrick Bouvier" wrote:
>>
>> So we could have something like:
>>
>> /* plugin side */
>> void on_cf_event(qemu_plugin_cf_event_type, uint64_t from, uint64_t to) {
>> ...
>> }
>
> We also need the VCPU id, but yes.
Yes!
>
>> /* API side */
>> void qemu_plugin_register_vcpu_syscall_cb(
>> qemu_plugin_id_t id, qemu_plugin_cf_event_type type, qemu_plugin_register_vcpu_cf_cb);
>>
>> We thus would have a new callback type qemu_plugin_vcpu_cf_cb_t added.
>>
>> For registering several events, we might define enum values for types indexed on every bit, so we can directly xor the enum to register several types. (same idea than existing qemu_plugin_mem_rw, but for more values, with a specific ALL value covering all possibilities).
>>
>> Does that match what you were thinking?
>
> Yes.
>
> Regards,
> Julian
^ permalink raw reply [flat|nested] 35+ messages in thread