Signed-off-by: Pierrick Bouvier <pierrick.bouv...@linaro.org>
---
contrib/plugins/uftrace.c | 85 +++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/contrib/plugins/uftrace.c b/contrib/plugins/uftrace.c
index 6628b4256fd..f10172eed10 100644
--- a/contrib/plugins/uftrace.c
+++ b/contrib/plugins/uftrace.c
@@ -79,6 +79,20 @@ typedef struct {
struct qemu_plugin_register *reg_scr_el3;
} Aarch64Cpu;
+typedef enum {
+ X64_RING0,
+ X64_RING1,
+ X64_RING2,
+ X64_RING3,
+ X64_REAL_MODE,
+} 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;
@@ -565,6 +579,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_REAL_MODE + 1;
+}
+
+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);
@@ -771,6 +854,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);
--
2.47.2