From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
"Manos Pitsidianakis" <manos.pitsidianakis@linaro.org>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Alexandre Iooss" <erdnaxe@crans.org>,
"Mahmoud Mandour" <ma.mandourr@gmail.com>
Subject: [PULL 17/24] contrib/plugins/uftrace: define cpu operations and implement aarch64
Date: Fri, 26 Sep 2025 14:17:36 +0100 [thread overview]
Message-ID: <20250926131744.432185-18-alex.bennee@linaro.org> (raw)
In-Reply-To: <20250926131744.432185-1-alex.bennee@linaro.org>
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
We define a new CpuOps structure that will be used to implement tracking
independently of guest architecture.
As well, we now instrument only instructions following ones that might
have touched the frame pointer.
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Message-ID: <20250902075042.223990-3-pierrick.bouvier@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250922093711.2768983-19-alex.bennee@linaro.org>
diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c
index 4af0130b159..d060513446c 100644
--- a/contrib/plugins/uftrace.c
+++ b/contrib/plugins/uftrace.c
@@ -11,14 +11,94 @@
#include <qemu-plugin.h>
#include <glib.h>
+#include <stdio.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+typedef struct Cpu Cpu;
+
+typedef struct {
+ void (*init)(Cpu *cpu);
+ void (*end)(Cpu *cpu);
+ uint64_t (*get_frame_pointer)(Cpu *cpu);
+ bool (*does_insn_modify_frame_pointer)(const char *disas);
+} CpuOps;
+
typedef struct Cpu {
GByteArray *buf;
+ CpuOps ops;
+ void *arch;
} Cpu;
+typedef struct {
+ struct qemu_plugin_register *reg_fp;
+} Aarch64Cpu;
+
static struct qemu_plugin_scoreboard *score;
+static CpuOps arch_ops;
+
+static uint64_t cpu_read_register64(Cpu *cpu, struct qemu_plugin_register *reg)
+{
+ GByteArray *buf = cpu->buf;
+ g_byte_array_set_size(buf, 0);
+ size_t sz = qemu_plugin_read_register(reg, buf);
+ g_assert(sz == 8);
+ g_assert(buf->len == 8);
+ return *((uint64_t *) buf->data);
+}
+
+static struct qemu_plugin_register *plugin_find_register(const char *name)
+{
+ g_autoptr(GArray) regs = qemu_plugin_get_registers();
+ for (int i = 0; i < regs->len; ++i) {
+ qemu_plugin_reg_descriptor *reg;
+ reg = &g_array_index(regs, qemu_plugin_reg_descriptor, i);
+ if (!strcmp(reg->name, name)) {
+ return reg->handle;
+ }
+ }
+ return NULL;
+}
+
+static uint64_t aarch64_get_frame_pointer(Cpu *cpu_)
+{
+ Aarch64Cpu *cpu = cpu_->arch;
+ return cpu_read_register64(cpu_, cpu->reg_fp);
+}
+
+static void aarch64_init(Cpu *cpu_)
+{
+ Aarch64Cpu *cpu = g_new0(Aarch64Cpu, 1);
+ cpu_->arch = cpu;
+ cpu->reg_fp = plugin_find_register("x29");
+ if (!cpu->reg_fp) {
+ fprintf(stderr, "uftrace plugin: frame pointer register (x29) is not "
+ "available. Please use an AArch64 cpu (or -cpu max).\n");
+ g_abort();
+ }
+}
+
+static void aarch64_end(Cpu *cpu)
+{
+ g_free(cpu->arch);
+}
+
+static bool aarch64_does_insn_modify_frame_pointer(const char *disas)
+{
+ /*
+ * Check if current instruction concerns fp register "x29".
+ * We add a prefix space to make sure we don't match addresses dump
+ * in disassembly.
+ */
+ return strstr(disas, " x29");
+}
+
+static CpuOps aarch64_ops = {
+ .init = aarch64_init,
+ .end = aarch64_end,
+ .get_frame_pointer = aarch64_get_frame_pointer,
+ .does_insn_modify_frame_pointer = aarch64_does_insn_modify_frame_pointer,
+};
static void track_callstack(unsigned int cpu_index, void *udata)
{
@@ -28,19 +108,37 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
size_t n_insns = qemu_plugin_tb_n_insns(tb);
+ /*
+ * Callbacks and inline instrumentation are inserted before an instruction.
+ * Thus, to see instruction effect, we need to wait for next one.
+ * Potentially, the last instruction of a block could modify the frame
+ * pointer. Thus, we need to always instrument first instruction in a tb.
+ */
+ bool instrument_insn = true;
for (size_t i = 0; i < n_insns; i++) {
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
- uintptr_t pc = qemu_plugin_insn_vaddr(insn);
- qemu_plugin_register_vcpu_insn_exec_cb(insn, track_callstack,
- QEMU_PLUGIN_CB_R_REGS,
- (void *) pc);
+ if (instrument_insn) {
+ uintptr_t pc = qemu_plugin_insn_vaddr(insn);
+ qemu_plugin_register_vcpu_insn_exec_cb(insn, track_callstack,
+ QEMU_PLUGIN_CB_R_REGS,
+ (void *) pc);
+ instrument_insn = false;
+ }
+
+ char *disas = qemu_plugin_insn_disas(insn);
+ if (arch_ops.does_insn_modify_frame_pointer(disas)) {
+ instrument_insn = true;
+ }
}
}
static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
{
Cpu *cpu = qemu_plugin_scoreboard_find(score, vcpu_index);
+ cpu->ops = arch_ops;
+
+ cpu->ops.init(cpu);
cpu->buf = g_byte_array_new();
}
@@ -64,6 +162,14 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info,
int argc, char **argv)
{
+ if (!strcmp(info->target_name, "aarch64")) {
+ arch_ops = aarch64_ops;
+ } else {
+ fprintf(stderr, "plugin uftrace: %s target is not supported\n",
+ info->target_name);
+ return 1;
+ }
+
score = qemu_plugin_scoreboard_new(sizeof(Cpu));
qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
qemu_plugin_register_atexit_cb(id, at_exit, NULL);
--
2.47.3
next prev parent reply other threads:[~2025-09-26 13:25 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-26 13:17 [PULL 00/24] maintainer updates (scripts, semihosting, plugins) Alex Bennée
2025-09-26 13:17 ` [PULL 01/24] scripts/ci: add gitlab-failure-analysis script Alex Bennée
2025-09-26 13:17 ` [PULL 02/24] checkpatch: Ignore removed lines in license check Alex Bennée
2025-09-26 13:17 ` [PULL 03/24] semihosting/syscalls: compile once in system and per target for user mode Alex Bennée
2025-09-26 13:17 ` [PULL 04/24] semihosting/syscalls: replace uint64_t with vaddr where appropriate Alex Bennée
2025-09-26 13:17 ` [PULL 05/24] semihosting/guestfd: compile once for system/user Alex Bennée
2025-09-26 13:17 ` [PULL 06/24] semihosting/arm-compat-semi: change common_semi_sys_exit_extended Alex Bennée
2025-09-26 13:17 ` [PULL 07/24] target/riscv/common-semi-target: remove sizeof(target_ulong) Alex Bennée
2025-09-26 13:17 ` [PULL 08/24] target/{arm, riscv}/common-semi-target: eradicate target_ulong Alex Bennée
2025-09-26 13:17 ` [PULL 09/24] include/semihosting/common-semi: extract common_semi API Alex Bennée
2025-09-26 13:17 ` [PULL 10/24] semihosting/arm-compat-semi: eradicate sizeof(target_ulong) Alex Bennée
2025-09-26 13:17 ` [PULL 11/24] semihosting/arm-compat-semi: replace target_ulong Alex Bennée
2025-09-26 13:17 ` [PULL 12/24] semihosting/arm-compat-semi: eradicate target_long Alex Bennée
2025-09-26 13:17 ` [PULL 13/24] semihosting/arm-compat-semi: remove dependency on cpu.h Alex Bennée
2025-09-26 13:17 ` [PULL 14/24] semihosting/arm-compat-semi: compile once in system and per target for user mode Alex Bennée
2025-09-26 13:17 ` [PULL 15/24] contrib/plugins/execlog: Explicitly check for qemu_plugin_read_register() failure Alex Bennée
2025-09-26 13:17 ` [PULL 16/24] contrib/plugins/uftrace: skeleton file Alex Bennée
2025-09-26 13:17 ` Alex Bennée [this message]
2025-09-26 13:17 ` [PULL 18/24] contrib/plugins/uftrace: track callstack Alex Bennée
2025-09-26 13:17 ` [PULL 19/24] contrib/plugins/uftrace: implement tracing Alex Bennée
2025-09-26 13:17 ` [PULL 20/24] contrib/plugins/uftrace: implement privilege level tracing Alex Bennée
2025-09-26 13:17 ` [PULL 21/24] contrib/plugins/uftrace: generate additional files for uftrace Alex Bennée
2025-09-26 13:17 ` [PULL 22/24] contrib/plugins/uftrace: implement x64 support Alex Bennée
2025-09-26 13:17 ` [PULL 23/24] contrib/plugins/uftrace_symbols.py Alex Bennée
2025-09-26 13:17 ` [PULL 24/24] contrib/plugins/uftrace: add documentation Alex Bennée
2025-09-27 15:42 ` [PULL 00/24] maintainer updates (scripts, semihosting, plugins) Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250926131744.432185-18-alex.bennee@linaro.org \
--to=alex.bennee@linaro.org \
--cc=erdnaxe@crans.org \
--cc=ma.mandourr@gmail.com \
--cc=manos.pitsidianakis@linaro.org \
--cc=pierrick.bouvier@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).