mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 14:04:39 +08:00
contrib/plugins/uftrace: add support for Hexagon
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com> Acked-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/20260930175519.3601312-1-brian.cain@oss.qualcomm.com Signed-off-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
This commit is contained in:
1 parent
d7a65d1793
commit
be2573eb08
2 files changed
+131
-1
No files matched your search
@@ -99,6 +99,19 @@ typedef struct {
|
||||
struct qemu_plugin_register *reg_cr0;
|
||||
} X64Cpu;
|
||||
|
||||
typedef enum {
|
||||
HEX_MONITOR,
|
||||
HEX_GUEST,
|
||||
HEX_USER,
|
||||
HEX_PRIVILEGE_LEVEL_MAX,
|
||||
} HexagonPrivilegeLevel;
|
||||
|
||||
typedef struct {
|
||||
struct qemu_plugin_register *reg_fp;
|
||||
struct qemu_plugin_register *reg_ssr;
|
||||
struct qemu_plugin_register *reg_framekey;
|
||||
} HexagonCPU;
|
||||
|
||||
typedef struct {
|
||||
struct qemu_plugin_register *reg_fp;
|
||||
struct qemu_plugin_register *reg_priv;
|
||||
@@ -453,6 +466,21 @@ static uint64_t cpu_read_memory64(Cpu *cpu, uint64_t addr)
|
||||
return *((uint64_t *) buf->data);
|
||||
}
|
||||
|
||||
static uint32_t cpu_read_memory32(Cpu *cpu, uint64_t addr)
|
||||
{
|
||||
if (!addr) {
|
||||
return 0;
|
||||
}
|
||||
GByteArray *buf = cpu->buf;
|
||||
g_byte_array_set_size(buf, 0);
|
||||
bool read = qemu_plugin_read_memory_vaddr(addr, buf, 4);
|
||||
if (!read) {
|
||||
return 0;
|
||||
}
|
||||
g_assert(buf->len == 4);
|
||||
return *((uint32_t *) buf->data);
|
||||
}
|
||||
|
||||
static void cpu_unwind_stack(Cpu *cpu, uint64_t frame_pointer, uint64_t pc)
|
||||
{
|
||||
g_assert(callstack_empty(cpu->cs));
|
||||
@@ -698,6 +726,106 @@ static CpuOps x64_ops = {
|
||||
.does_insn_modify_frame_pointer = x64_does_insn_modify_frame_pointer,
|
||||
};
|
||||
|
||||
static uint8_t hexagon_num_privilege_levels(void)
|
||||
{
|
||||
return HEX_PRIVILEGE_LEVEL_MAX;
|
||||
}
|
||||
|
||||
static const char *hexagon_get_privilege_level_name(uint8_t pl)
|
||||
{
|
||||
switch (pl) {
|
||||
case HEX_MONITOR: return "monitor";
|
||||
case HEX_GUEST: return "guest";
|
||||
case HEX_USER: return "user";
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
#define HEX_SSR_FIELD_UM 16
|
||||
#define HEX_SSR_FIELD_EX 17
|
||||
#define HEX_SSR_FIELD_GM 19
|
||||
|
||||
static uint8_t hexagon_get_privilege_level(Cpu *cpu_)
|
||||
{
|
||||
HexagonCPU *cpu = cpu_->arch;
|
||||
uint32_t ssr = cpu_read_register32(cpu_, cpu->reg_ssr);
|
||||
bool ex = (ssr >> HEX_SSR_FIELD_EX) & 1;
|
||||
bool um = (ssr >> HEX_SSR_FIELD_UM) & 1;
|
||||
bool gm = (ssr >> HEX_SSR_FIELD_GM) & 1;
|
||||
|
||||
if (ex || !um) {
|
||||
return HEX_MONITOR;
|
||||
} else if (!ex && um) {
|
||||
return gm ? HEX_GUEST : HEX_USER;
|
||||
}
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static uint64_t hexagon_get_frame_pointer(Cpu *cpu_)
|
||||
{
|
||||
HexagonCPU *cpu = cpu_->arch;
|
||||
return cpu_read_register32(cpu_, cpu->reg_fp);
|
||||
}
|
||||
|
||||
static uint64_t hexagon_get_next_frame_pointer(Cpu *cpu_, uint64_t fp)
|
||||
{
|
||||
return cpu_read_memory32(cpu_, fp);
|
||||
}
|
||||
|
||||
static uint64_t hexagon_get_next_return_address(Cpu *cpu_,
|
||||
uint64_t frame_pointer)
|
||||
{
|
||||
HexagonCPU *cpu = cpu_->arch;
|
||||
uint64_t framekey = cpu_read_register32(cpu_, cpu->reg_framekey);
|
||||
uint64_t scrambled_lr = cpu_read_memory32(cpu_, frame_pointer + 4);
|
||||
uint64_t lr = scrambled_lr ^ framekey;
|
||||
return lr;
|
||||
}
|
||||
|
||||
static void hexagon_init(Cpu *cpu_)
|
||||
{
|
||||
HexagonCPU *cpu = g_new0(HexagonCPU, 1);
|
||||
cpu_->arch = cpu;
|
||||
cpu->reg_fp = plugin_find_register("r30");
|
||||
if (!cpu->reg_fp) {
|
||||
fprintf(stderr, "uftrace plugin: frame pointer register (R30) is not "
|
||||
"available.\n");
|
||||
g_abort();
|
||||
}
|
||||
cpu->reg_ssr = plugin_find_register("ssr");
|
||||
if (trace_privilege_level && !cpu->reg_ssr) {
|
||||
fprintf(stderr, "uftrace plugin: trace-privilege-level is not "
|
||||
"supported for hexagon-linux-user.\n");
|
||||
g_abort();
|
||||
}
|
||||
cpu->reg_framekey = plugin_find_register("framekey");
|
||||
g_assert(cpu->reg_framekey);
|
||||
}
|
||||
|
||||
static void hexagon_end(Cpu *cpu)
|
||||
{
|
||||
g_free(cpu->arch);
|
||||
}
|
||||
|
||||
static bool hexagon_does_insn_modify_frame_pointer(const char *disas)
|
||||
{
|
||||
return strstr(disas, "alloc") ||
|
||||
strstr(disas, "R30") || strstr(disas, "R31:30");
|
||||
}
|
||||
|
||||
static CpuOps hexagon_ops = {
|
||||
.init = hexagon_init,
|
||||
.end = hexagon_end,
|
||||
.get_frame_pointer = hexagon_get_frame_pointer,
|
||||
.get_next_frame_pointer = hexagon_get_next_frame_pointer,
|
||||
.get_next_return_address = hexagon_get_next_return_address,
|
||||
.get_privilege_level = hexagon_get_privilege_level,
|
||||
.num_privilege_levels = hexagon_num_privilege_levels,
|
||||
.get_privilege_level_name = hexagon_get_privilege_level_name,
|
||||
.does_insn_modify_frame_pointer = hexagon_does_insn_modify_frame_pointer,
|
||||
};
|
||||
|
||||
static uint8_t riscv64_num_privilege_levels(void)
|
||||
{
|
||||
return RISCV64_PRIVILEGE_LEVEL_MAX;
|
||||
@@ -984,6 +1112,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
arch_ops = x64_ops;
|
||||
} else if (!strcmp(info->target_name, "riscv64")) {
|
||||
arch_ops = riscv64_ops;
|
||||
} else if (!strcmp(info->target_name, "hexagon")) {
|
||||
arch_ops = hexagon_ops;
|
||||
} else {
|
||||
fprintf(stderr, "plugin uftrace: %s target is not supported\n",
|
||||
info->target_name);
|
||||
|
||||
@@ -836,7 +836,7 @@ Uftrace
|
||||
This plugin generates a binary trace compatible with
|
||||
`uftrace <https://github.com/namhyung/uftrace>`_.
|
||||
|
||||
Plugin supports aarch64, x64 and riscv64, and works in user and system mode,
|
||||
Plugin supports aarch64, x64, riscv64, and Hexagon, and works in user and system mode,
|
||||
allowing to trace a system boot, which is not something possible usually.
|
||||
|
||||
In user mode, the memory mapping is directly copied from ``/proc/self/maps`` at
|
||||
|
||||
Reference in new issue
Block a user