contrib/plugins/uftrace: skeleton file

We define a scoreboard that will hold our data per cpu. As well, we
define a buffer per cpu that will be used to read registers and memories
in a thread-safe way.

For now, we just instrument all instructions with an empty callback.

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Message-ID: <20250902075042.223990-2-pierrick.bouvier@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250922093711.2768983-18-alex.bennee@linaro.org>
This commit is contained in:
Pierrick Bouvier
2025-09-22 10:37:02 +01:00
committed by Alex Bennée
parent 04387b4a05
commit 293028ca25
2 changed files with 75 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
contrib_plugins = ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotblocks',
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger']
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger',
'uftrace']
if host_os != 'windows'
# lockstep uses socket.h
contrib_plugins += 'lockstep'

73
contrib/plugins/uftrace.c Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2025, Pierrick Bouvier <pierrick.bouvier@linaro.org>
*
* Generates a trace compatible with uftrace (similar to uftrace record).
* https://github.com/namhyung/uftrace
*
* See docs/about/emulation.rst|Uftrace for details and examples.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <qemu-plugin.h>
#include <glib.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
typedef struct Cpu {
GByteArray *buf;
} Cpu;
static struct qemu_plugin_scoreboard *score;
static void track_callstack(unsigned int cpu_index, void *udata)
{
}
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);
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);
}
}
static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
{
Cpu *cpu = qemu_plugin_scoreboard_find(score, vcpu_index);
cpu->buf = g_byte_array_new();
}
static void vcpu_end(unsigned int vcpu_index)
{
Cpu *cpu = qemu_plugin_scoreboard_find(score, vcpu_index);
g_byte_array_free(cpu->buf, true);
memset(cpu, 0, sizeof(Cpu));
}
static void at_exit(qemu_plugin_id_t id, void *data)
{
for (size_t i = 0; i < qemu_plugin_num_vcpus(); ++i) {
vcpu_end(i);
}
qemu_plugin_scoreboard_free(score);
}
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info,
int argc, char **argv)
{
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);
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
return 0;
}