contrib/plugins/uftrace: implement x64 support

It's trivial to implement x64 support, as it's the same stack layout
as aarch64.

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Message-ID: <20250902075042.223990-8-pierrick.bouvier@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250922093711.2768983-24-alex.bennee@linaro.org>
This commit is contained in:
Pierrick Bouvier 2025-09-22 10:37:08 +01:00 committed by Alex Bennée
parent 7278747595
commit b860d96f00

View file

@ -82,6 +82,21 @@ typedef struct {
struct qemu_plugin_register *reg_scr_el3;
} Aarch64Cpu;
typedef enum {
X64_RING0,
X64_RING1,
X64_RING2,
X64_RING3,
X64_REAL_MODE,
X64_PRIVILEGE_LEVEL_MAX,
} X64PrivilegeLevel;
typedef struct {
struct qemu_plugin_register *reg_rbp;
struct qemu_plugin_register *reg_cs;
struct qemu_plugin_register *reg_cr0;
} X64Cpu;
typedef struct {
uint64_t timestamp;
uint64_t data;
@ -570,6 +585,75 @@ static CpuOps aarch64_ops = {
.does_insn_modify_frame_pointer = aarch64_does_insn_modify_frame_pointer,
};
static uint8_t x64_num_privilege_levels(void)
{
return X64_PRIVILEGE_LEVEL_MAX;
}
static const char *x64_get_privilege_level_name(uint8_t pl)
{
switch (pl) {
case X64_RING0: return "Ring0";
case X64_RING1: return "Ring1";
case X64_RING2: return "Ring2";
case X64_RING3: return "Ring3";
case X64_REAL_MODE: return "RealMode";
default:
g_assert_not_reached();
}
}
static uint8_t x64_get_privilege_level(Cpu *cpu_)
{
X64Cpu *cpu = cpu_->arch;
uint64_t cr0 = cpu_read_register64(cpu_, cpu->reg_cr0);
uint64_t protected_mode = (cr0 >> 0) & 0b1;
if (!protected_mode) {
return X64_REAL_MODE;
}
uint32_t cs = cpu_read_register32(cpu_, cpu->reg_cs);
uint32_t ring_level = (cs >> 0) & 0b11;
return ring_level;
}
static uint64_t x64_get_frame_pointer(Cpu *cpu_)
{
X64Cpu *cpu = cpu_->arch;
return cpu_read_register64(cpu_, cpu->reg_rbp);
}
static void x64_init(Cpu *cpu_)
{
X64Cpu *cpu = g_new0(X64Cpu, 1);
cpu_->arch = cpu;
cpu->reg_rbp = plugin_find_register("rbp");
g_assert(cpu->reg_rbp);
cpu->reg_cs = plugin_find_register("cs");
g_assert(cpu->reg_cs);
cpu->reg_cr0 = plugin_find_register("cr0");
g_assert(cpu->reg_cr0);
}
static void x64_end(Cpu *cpu)
{
g_free(cpu->arch);
}
static bool x64_does_insn_modify_frame_pointer(const char *disas)
{
return strstr(disas, "rbp");
}
static CpuOps x64_ops = {
.init = x64_init,
.end = x64_end,
.get_frame_pointer = x64_get_frame_pointer,
.get_privilege_level = x64_get_privilege_level,
.num_privilege_levels = x64_num_privilege_levels,
.get_privilege_level_name = x64_get_privilege_level_name,
.does_insn_modify_frame_pointer = x64_does_insn_modify_frame_pointer,
};
static void track_privilege_change(unsigned int cpu_index, void *udata)
{
Cpu *cpu = qemu_plugin_scoreboard_find(score, cpu_index);
@ -777,6 +861,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
if (!strcmp(info->target_name, "aarch64")) {
arch_ops = aarch64_ops;
} else if (!strcmp(info->target_name, "x86_64")) {
arch_ops = x64_ops;
} else {
fprintf(stderr, "plugin uftrace: %s target is not supported\n",
info->target_name);