qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Palmer Dabbelt" <palmer@dabbelt.com>,
	"Alexandre Iooss" <erdnaxe@crans.org>,
	"Mahmoud Mandour" <ma.mandourr@gmail.com>,
	qemu-riscv@nongnu.org,
	"Daniel Henrique Barboza" <dbarboza@ventanamicro.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Alistair Francis" <alistair.francis@wdc.com>,
	qemu-arm@nongnu.org, "Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Weiwei Li" <liwei1518@gmail.com>,
	"Pierrick Bouvier" <pierrick.bouvier@linaro.org>,
	"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>,
	"Manos Pitsidianakis" <manos.pitsidianakis@linaro.org>
Subject: [PATCH 18/25] contrib/plugins/uftrace: define cpu operations and implement aarch64
Date: Mon, 22 Sep 2025 10:37:03 +0100	[thread overview]
Message-ID: <20250922093711.2768983-19-alex.bennee@linaro.org> (raw)
In-Reply-To: <20250922093711.2768983-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>
---
 contrib/plugins/uftrace.c | 114 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 110 insertions(+), 4 deletions(-)

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



  parent reply	other threads:[~2025-09-22  9:47 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-22  9:36 [PATCH 00/25] September maintainer updates (docs, plugins, semihosting) pre-PR Alex Bennée
2025-09-22  9:36 ` [PATCH 01/25] docs/devel: fix typo in code-provenance.rst Alex Bennée
2025-09-22 11:32   ` Thomas Huth
2025-09-22 19:37   ` Richard Henderson
2025-09-22  9:36 ` [PATCH 02/25] scripts/ci: add gitlab-failure-analysis script Alex Bennée
2025-09-22  9:36 ` [PATCH 03/25] checkpatch: Ignore removed lines in license check Alex Bennée
2025-09-22  9:36 ` [PATCH 04/25] semihosting/syscalls: compile once in system and per target for user mode Alex Bennée
2025-09-22  9:36 ` [PATCH 05/25] semihosting/syscalls: replace uint64_t with vaddr where appropriate Alex Bennée
2025-09-22  9:36 ` [PATCH 06/25] semihosting/guestfd: compile once for system/user Alex Bennée
2025-09-22  9:36 ` [PATCH 07/25] semihosting/arm-compat-semi: change common_semi_sys_exit_extended Alex Bennée
2025-09-22  9:36 ` [PATCH 08/25] target/riscv/common-semi-target: remove sizeof(target_ulong) Alex Bennée
2025-09-22  9:36 ` [PATCH 09/25] target/{arm, riscv}/common-semi-target: eradicate target_ulong Alex Bennée
2025-09-22  9:36 ` [PATCH 10/25] include/semihosting/common-semi: extract common_semi API Alex Bennée
2025-09-22  9:36 ` [PATCH 11/25] semihosting/arm-compat-semi: eradicate sizeof(target_ulong) Alex Bennée
2025-09-22 11:52   ` Philippe Mathieu-Daudé
2025-09-22  9:36 ` [PATCH 12/25] semihosting/arm-compat-semi: replace target_ulong with vaddr Alex Bennée
2025-09-22 11:53   ` Philippe Mathieu-Daudé
2025-09-22 12:43     ` Alex Bennée
2025-09-25 21:13       ` Pierrick Bouvier
2025-09-22  9:36 ` [PATCH 13/25] semihosting/arm-compat-semi: eradicate target_long Alex Bennée
2025-09-22  9:36 ` [PATCH 14/25] semihosting/arm-compat-semi: remove dependency on cpu.h Alex Bennée
2025-09-22  9:37 ` [PATCH 15/25] semihosting/arm-compat-semi: compile once in system and per target for user mode Alex Bennée
2025-09-22  9:37 ` [PATCH 16/25] contrib/plugins/execlog: Explicitly check for qemu_plugin_read_register() failure Alex Bennée
2025-09-22  9:37 ` [PATCH 17/25] contrib/plugins/uftrace: skeleton file Alex Bennée
2025-09-22  9:37 ` Alex Bennée [this message]
2025-09-22  9:37 ` [PATCH 19/25] contrib/plugins/uftrace: track callstack Alex Bennée
2025-09-22  9:37 ` [PATCH 20/25] contrib/plugins/uftrace: implement tracing Alex Bennée
2025-09-22  9:37 ` [PATCH 21/25] contrib/plugins/uftrace: implement privilege level tracing Alex Bennée
2025-09-22  9:37 ` [PATCH 22/25] contrib/plugins/uftrace: generate additional files for uftrace Alex Bennée
2025-09-22  9:37 ` [PATCH 23/25] contrib/plugins/uftrace: implement x64 support Alex Bennée
2025-09-22  9:37 ` [PATCH 24/25] contrib/plugins/uftrace_symbols.py Alex Bennée
2025-09-22  9:37 ` [PATCH 25/25] contrib/plugins/uftrace: add documentation Alex Bennée

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=20250922093711.2768983-19-alex.bennee@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=alistair.francis@wdc.com \
    --cc=dbarboza@ventanamicro.com \
    --cc=erdnaxe@crans.org \
    --cc=liwei1518@gmail.com \
    --cc=ma.mandourr@gmail.com \
    --cc=manos.pitsidianakis@linaro.org \
    --cc=palmer@dabbelt.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=thuth@redhat.com \
    --cc=zhiwei_liu@linux.alibaba.com \
    /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).