[PATCH v8 03/17] perf capstone: Determine architecture from e_machine

From: Ian Rogers

Date: Sat May 02 2026 - 03:00:31 EST


Avoid the use of arch string that is imprecise and use the
e_machine. Do more e_machine to capstone machine translations adding
MIPS and RISCV. Remove unnecessary maybe_unused annotations.

Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/util/capstone.c | 115 +++++++++++++++++++++++++------------
1 file changed, 79 insertions(+), 36 deletions(-)

diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
index 25cf6e15ec27..e6226b751c36 100644
--- a/tools/perf/util/capstone.c
+++ b/tools/perf/util/capstone.c
@@ -16,6 +16,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <string.h>
+#include <elf.h>

#include <capstone/capstone.h>

@@ -137,37 +138,74 @@ static enum cs_err perf_cs_close(csh *handle)
#endif
}

-static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
- bool disassembler_style)
+static bool e_machine_to_capstone(uint16_t e_machine, bool is64,
+ enum cs_arch *arch, enum cs_mode *mode)
+{
+ switch (e_machine) {
+ case EM_X86_64:
+ *arch = CS_ARCH_X86;
+ *mode = CS_MODE_64;
+ return true;
+ case EM_386:
+ *arch = CS_ARCH_X86;
+ *mode = CS_MODE_32;
+ return true;
+ case EM_AARCH64:
+ *arch = CS_ARCH_ARM64;
+ *mode = CS_MODE_ARM;
+ return true;
+ case EM_ARM:
+ *arch = CS_ARCH_ARM;
+ *mode = CS_MODE_ARM | CS_MODE_V8;
+ return true;
+ case EM_S390:
+ *arch = CS_ARCH_SYSZ;
+ *mode = CS_MODE_BIG_ENDIAN;
+ return true;
+ case EM_MIPS:
+ *arch = CS_ARCH_MIPS;
+ *mode = is64 ? CS_MODE_MIPS64 : CS_MODE_MIPS32;
+ *mode |= CS_MODE_BIG_ENDIAN;
+ return true;
+ case EM_PPC:
+ *arch = CS_ARCH_PPC;
+ *mode = CS_MODE_BIG_ENDIAN | CS_MODE_32;
+ return true;
+ case EM_PPC64:
+ *arch = CS_ARCH_PPC;
+ *mode = CS_MODE_BIG_ENDIAN | CS_MODE_64;
+ return true;
+ case EM_SPARC:
+ *arch = CS_ARCH_SPARC;
+ *mode = CS_MODE_BIG_ENDIAN | CS_MODE_32;
+ return true;
+ case EM_SPARCV9:
+ *arch = CS_ARCH_SPARC;
+ *mode = CS_MODE_BIG_ENDIAN | CS_MODE_V9 | CS_MODE_64;
+ return true;
+ case EM_RISCV:
+ *arch = CS_ARCH_RISCV;
+ *mode = is64 ? CS_MODE_RISCV64 : CS_MODE_RISCV32;
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int capstone_init(uint16_t e_machine, csh *cs_handle, bool is64, bool disassembler_style)
{
enum cs_arch arch;
enum cs_mode mode;

- if (machine__is(machine, "x86_64") && is64) {
- arch = CS_ARCH_X86;
- mode = CS_MODE_64;
- } else if (machine__normalized_is(machine, "x86")) {
- arch = CS_ARCH_X86;
- mode = CS_MODE_32;
- } else if (machine__normalized_is(machine, "arm64")) {
- arch = CS_ARCH_ARM64;
- mode = CS_MODE_ARM;
- } else if (machine__normalized_is(machine, "arm")) {
- arch = CS_ARCH_ARM;
- mode = CS_MODE_ARM + CS_MODE_V8;
- } else if (machine__normalized_is(machine, "s390")) {
- arch = CS_ARCH_SYSZ;
- mode = CS_MODE_BIG_ENDIAN;
- } else {
+ if (!e_machine_to_capstone(e_machine, is64, &arch, &mode))
return -1;
- }

if (perf_cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
pr_warning_once("cs_open failed\n");
return -1;
}

- if (machine__normalized_is(machine, "x86")) {
+ if (arch == CS_ARCH_X86) {
/*
* In case of using capstone_init while symbol__disassemble
* setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts
@@ -212,28 +250,31 @@ static size_t print_insn_x86(struct thread *thread, u8 cpumode, struct cs_insn *
}


-ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
- struct thread *thread __maybe_unused,
- u8 cpumode __maybe_unused, bool is64bit __maybe_unused,
- const uint8_t *code __maybe_unused,
- size_t code_size __maybe_unused,
- uint64_t ip __maybe_unused, int *lenp __maybe_unused,
- int print_opts __maybe_unused, FILE *fp __maybe_unused)
+ssize_t capstone__fprintf_insn_asm(struct machine *machine,
+ struct thread *thread,
+ u8 cpumode,
+ bool is64bit,
+ const uint8_t *code,
+ size_t code_size,
+ uint64_t ip, int *lenp,
+ int print_opts,
+ FILE *fp)
{
size_t printed;
struct cs_insn *insn;
csh cs_handle;
size_t count;
+ uint16_t e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL);
int ret;

/* TODO: Try to initiate capstone only once but need a proper place. */
- ret = capstone_init(machine, &cs_handle, is64bit, true);
+ ret = capstone_init(e_machine, &cs_handle, is64bit, /*disassembler_style=*/true);
if (ret < 0)
return ret;

count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
if (count > 0) {
- if (machine__normalized_is(machine, "x86"))
+ if (e_machine == EM_X86_64 || e_machine == EM_386)
printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
else
printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
@@ -322,9 +363,9 @@ static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg)
return 0;
}

-int symbol__disassemble_capstone(const char *filename __maybe_unused,
- struct symbol *sym __maybe_unused,
- struct annotate_args *args __maybe_unused)
+int symbol__disassemble_capstone(const char *filename,
+ struct symbol *sym,
+ struct annotate_args *args)
{
struct annotation *notes = symbol__annotation(sym);
struct map *map = args->ms->map;
@@ -344,6 +385,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
char disasm_buf[512];
struct disasm_line *dl;
bool disassembler_style = false;
+ uint16_t e_machine;

if (args->options->objdump_path)
return -1;
@@ -373,8 +415,8 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
!strcmp(args->options->disassembler_style, "att"))
disassembler_style = true;

- if (capstone_init(maps__machine(thread__maps(args->ms->thread)), &handle, is_64bit,
- disassembler_style) < 0)
+ e_machine = thread__e_machine(args->ms->thread, /*machine=*/NULL, /*e_flags=*/NULL);
+ if (capstone_init(e_machine, &handle, is_64bit, disassembler_style) < 0)
goto err;

needs_cs_close = true;
@@ -466,6 +508,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
struct disasm_line *dl;
u32 *line;
bool disassembler_style = false;
+ uint16_t e_machine;

if (args->options->objdump_path)
return -1;
@@ -484,8 +527,8 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
!strcmp(args->options->disassembler_style, "att"))
disassembler_style = true;

- if (capstone_init(maps__machine(thread__maps(args->ms->thread)), &handle, is_64bit,
- disassembler_style) < 0)
+ e_machine = thread__e_machine(args->ms->thread, /*machine=*/NULL, /*e_flags=*/NULL);
+ if (capstone_init(e_machine, &handle, is_64bit, disassembler_style) < 0)
goto err;

needs_cs_close = true;
--
2.54.0.545.g6539524ca2-goog