* [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support
@ 2026-06-09 7:07 Ian Rogers
2026-06-09 7:07 ` [PATCH v2 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
` (7 more replies)
0 siblings, 8 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
This series adds a new `libasm` disassembly backend to `perf annotate`,
leveraging the `elfutils` libasm library. This allows perf to use the
widely available elfutils for disassembly alongside capstone, libLLVM, and objdump.
v2 changes:
- Patch 1: Added a note to the commit message acknowledging that older elfutils static builds lacking `-lebl` dependencies in pkg-config are explicitly unsupported, while intentionally retaining the feature check and API dependencies.
- Patch 2: Fixed `NO_LIBELF=1` build breakages by implicitly disabling `libasm` and removing the unconditional `#warning` in favor of silent fallbacks or standard warnings.
- Patch 3: Fixed `libasm` block boundary tracking and corrected callback error/return values, preventing memory leaks and infinite loops in the disassembly extraction loop.
- Patch 5: Fixed script robustness in `tests/shell/annotate.sh` by ensuring cleanup functions run reliably, `set -e` doesn't abort prematurely on grep failures, and configs are properly restored.
- Patch 6: Refactored `jit_write_elf` to accept the `e_machine` parameter directly instead of post-patching the generated ELF file with `libelf`. The target architecture is now extracted dynamically and passed into `jit_write_elf`, simplifying the interaction with BPF and making it fully compatible with all disassemblers.
- Patch 7: Fixed a TOCTOU race condition when creating the symlink in `tests/shell/annotate.sh` by placing `perf.data` inside an isolated temporary directory.
- General: The cover letter now lists capstone, libLLVM, and objdump as the existing disassemblers instead of just objdump.
Ian Rogers (7):
tools build: Add feature check for elfutils libasm
perf build: Add build support and capability for elfutils libasm
perf annotate: Implement elfutils libasm disassembler backend
perf annotate: Add --disassembler command-line option
perf test: Enhance annotate test coverage and isolate config
perf annotate: Support BPF JIT disassembly via genelf
perf test: Add BPF JIT annotation test coverage for all disassemblers
tools/build/Makefile.feature | 2 +
tools/build/feature/Makefile | 9 ++
tools/build/feature/test-libasm.c | 19 +++
tools/perf/Makefile.config | 22 ++++
tools/perf/builtin-annotate.c | 10 ++
tools/perf/builtin-check.c | 1 +
tools/perf/tests/genelf.c | 2 +-
tools/perf/tests/shell/annotate.sh | 133 +++++++++++++++++++++
tools/perf/util/Build | 1 +
tools/perf/util/annotate.c | 8 +-
tools/perf/util/annotate.h | 3 +
tools/perf/util/disasm.c | 114 +++++++++++++++++-
tools/perf/util/disasm.h | 1 +
tools/perf/util/genelf.c | 4 +-
tools/perf/util/genelf.h | 2 +-
tools/perf/util/jitdump.c | 2 +-
tools/perf/util/libasm.c | 184 +++++++++++++++++++++++++++++
tools/perf/util/libasm.h | 27 +++++
18 files changed, 531 insertions(+), 13 deletions(-)
create mode 100644 tools/build/feature/test-libasm.c
create mode 100644 tools/perf/util/libasm.c
create mode 100644 tools/perf/util/libasm.h
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 1/7] tools build: Add feature check for elfutils libasm
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:21 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 2/7] perf build: Add build support and capability " Ian Rogers
` (6 subsequent siblings)
7 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
This commit introduces a build-time feature test for the elfutils libasm
library in the shared tools/build system. It adds the test program and
updates the Makefiles to attempt building it to detect support.
Note on static linking: pkg-config for libdw/libelf on modern systems
does not list -lebl as a dependency. Older versions of elfutils that
require explicitly linking -lebl statically are unsupported by this
feature check.
---
tools/build/Makefile.feature | 2 ++
tools/build/feature/Makefile | 9 +++++++++
tools/build/feature/test-libasm.c | 19 +++++++++++++++++++
3 files changed, 30 insertions(+)
create mode 100644 tools/build/feature/test-libasm.c
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index ed1374af31c1..422329dbc20a 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -118,6 +118,7 @@ FEATURE_TESTS_EXTRA := \
hello \
babeltrace2-ctf-writer \
libcapstone \
+ libasm \
libcheck \
libbfd-liberty \
libbfd-liberty-z \
@@ -150,6 +151,7 @@ FEATURE_DISPLAY ?= \
numa_num_possible_cpus \
libpython \
libcapstone \
+ libasm \
llvm-perf \
zlib \
lzma \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 62909a9c799d..f0f39a2ab203 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -47,6 +47,7 @@ FILES= \
test-timerfd.bin \
test-babeltrace2-ctf-writer.bin \
test-libcapstone.bin \
+ test-libasm.bin \
test-libcheck.bin \
test-compile-32.bin \
test-compile-x32.bin \
@@ -184,6 +185,11 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
DWARFLIBS += -ldl
endif
+ASMLIBS := -lasm -ldw -lelf
+ifeq ($(findstring -static,${LDFLAGS}),-static)
+ ASMLIBS += -lz -llzma -lbz2 -lzstd
+endif
+
$(OUTPUT)test-libdw.bin:
$(BUILD) $(DWLIBS)
@@ -311,6 +317,9 @@ $(OUTPUT)test-babeltrace2-ctf-writer.bin:
$(OUTPUT)test-libcapstone.bin:
$(BUILD) # -lcapstone provided by $(FEATURE_CHECK_LDFLAGS-libcapstone)
+$(OUTPUT)test-libasm.bin:
+ $(BUILD) $(ASMLIBS)
+
$(OUTPUT)test-libcheck.bin:
$(BUILD) # -lcheck is provided by $(FEATURE_CHECK_LDFLAGS-libcheck)
diff --git a/tools/build/feature/test-libasm.c b/tools/build/feature/test-libasm.c
new file mode 100644
index 000000000000..f3598ad1cc9e
--- /dev/null
+++ b/tools/build/feature/test-libasm.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stddef.h>
+#include <elfutils/libasm.h>
+#include <gelf.h>
+
+typedef struct ebl Ebl;
+extern Ebl *ebl_openbackend (Elf *elf);
+extern void ebl_closebackend (Ebl *ebl);
+
+int main(void)
+{
+ Elf *elf = elf_begin(0, ELF_C_READ, NULL);
+ Ebl *ebl = ebl_openbackend(elf);
+ DisasmCtx_t *ctx = disasm_begin(ebl, elf, NULL);
+ disasm_end(ctx);
+ ebl_closebackend(ebl);
+ elf_end(elf);
+ return 0;
+}
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 2/7] perf build: Add build support and capability for elfutils libasm
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
2026-06-09 7:07 ` [PATCH v2 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:19 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
` (5 subsequent siblings)
7 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
Configure perf build system to utilize the libasm feature check
(supporting both static and dynamic builds) and export the config flags.
Add "libasm" capability detection to perf check.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 22 ++++++++++++++++++++++
tools/perf/builtin-check.c | 1 +
2 files changed, 23 insertions(+)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 6e7b15fab2ec..8527d20f498f 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -199,6 +199,13 @@ endif
FEATURE_CHECK_CFLAGS-libcapstone := $(LIBCAPSTONE_CFLAGS)
FEATURE_CHECK_LDFLAGS-libcapstone := $(LIBCAPSTONE_LDFLAGS) -lcapstone
+ifdef LIBASM_DIR
+ LIBASM_CFLAGS := -I$(LIBASM_DIR)/include
+ LIBASM_LDFLAGS := -L$(LIBASM_DIR)/lib
+endif
+FEATURE_CHECK_CFLAGS-libasm := $(LIBASM_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libasm := $(LIBASM_LDFLAGS) -lasm -ldw -lelf
+
ifdef LIBZSTD_DIR
LIBZSTD_CFLAGS := -I$(LIBZSTD_DIR)/lib
LIBZSTD_LDFLAGS := -L$(LIBZSTD_DIR)/lib
@@ -432,6 +439,7 @@ ifeq ($(feature-file-handle), 1)
endif
ifdef NO_LIBELF
+ NO_LIBASM := 1
NO_LIBDW := 1
NO_LIBUNWIND := 1
NO_LIBBPF := 1
@@ -1060,6 +1068,20 @@ ifndef NO_CAPSTONE
endif
endif
+ifndef NO_LIBASM
+ $(call feature_check,libasm)
+ ifeq ($(feature-libasm), 1)
+ CFLAGS += -DHAVE_LIBASM_SUPPORT $(LIBASM_CFLAGS)
+ ifdef LIBASM_DLOPEN
+ CFLAGS += -DLIBASM_DLOPEN
+ else
+ LDFLAGS += $(LIBASM_LDFLAGS)
+ EXTLIBS += -lasm -ldw -lelf
+ endif
+ $(call detected,CONFIG_LIBASM)
+ endif
+endif
+
ifdef EXTRA_TESTS
$(call detected,CONFIG_EXTRA_TESTS)
CFLAGS += -DHAVE_EXTRA_TESTS
diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c
index 60437650c50f..d2ffea4d9b8b 100644
--- a/tools/perf/builtin-check.c
+++ b/tools/perf/builtin-check.c
@@ -46,6 +46,7 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("babeltrace2-ctf-writer", HAVE_BABELTRACE2_CTF_WRITER_SUPPORT),
FEATURE_STATUS("libbpf-strings", HAVE_LIBBPF_STRINGS_SUPPORT),
FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT),
+ FEATURE_STATUS("libasm", HAVE_LIBASM_SUPPORT),
FEATURE_STATUS("libdw-dwarf-unwind", HAVE_LIBDW_SUPPORT),
FEATURE_STATUS("libelf", HAVE_LIBELF_SUPPORT),
FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT),
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 3/7] perf annotate: Implement elfutils libasm disassembler backend
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
2026-06-09 7:07 ` [PATCH v2 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
2026-06-09 7:07 ` [PATCH v2 2/7] perf build: Add build support and capability " Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:07 ` [PATCH v2 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
` (4 subsequent siblings)
7 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
Implement the core disassembler backend in libasm.c utilizing elfutils'
libasm API. Hook the backend into perf annotate disassembler routing.
Configure libasm as the first-choice disassembler backend by default
(ahead of LLVM/capstone) when available.
Also, expose annotation_options__add_disassemblers_str to allow
custom disassembler selection.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/Build | 1 +
tools/perf/util/annotate.c | 8 +-
tools/perf/util/annotate.h | 3 +
tools/perf/util/disasm.c | 5 +
tools/perf/util/libasm.c | 184 +++++++++++++++++++++++++++++++++++++
tools/perf/util/libasm.h | 27 ++++++
6 files changed, 226 insertions(+), 2 deletions(-)
create mode 100644 tools/perf/util/libasm.c
create mode 100644 tools/perf/util/libasm.h
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b22cdc24082a..f1d5ebb2edfa 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -12,6 +12,7 @@ perf-util-y += block-range.o
perf-util-y += build-id.o
perf-util-y += cacheline.o
perf-util-$(CONFIG_LIBCAPSTONE) += capstone.o
+perf-util-$(CONFIG_LIBASM) += libasm.o
perf-util-y += config.o
perf-util-y += copyfile.o
perf-util-y += ctype.o
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 02505222d8c2..2259ac2c2cd6 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -2233,6 +2233,7 @@ const char * const perf_disassembler__strs[] = {
[PERF_DISASM_UNKNOWN] = "unknown",
[PERF_DISASM_LLVM] = "llvm",
[PERF_DISASM_CAPSTONE] = "capstone",
+ [PERF_DISASM_LIBASM] = "libasm",
[PERF_DISASM_OBJDUMP] = "objdump",
};
@@ -2254,8 +2255,8 @@ static void annotation_options__add_disassembler(struct annotation_options *opti
pr_err("Failed to add disassembler %d\n", dis);
}
-static int annotation_options__add_disassemblers_str(struct annotation_options *options,
- const char *str)
+int annotation_options__add_disassemblers_str(struct annotation_options *options,
+ const char *str)
{
while (str && *str != '\0') {
const char *comma = strchr(str, ',');
@@ -2372,6 +2373,9 @@ static void annotation_options__default_init_disassemblers(struct annotation_opt
/* Already initialized. */
return;
}
+#ifdef HAVE_LIBASM_SUPPORT
+ annotation_options__add_disassembler(options, PERF_DISASM_LIBASM);
+#endif
#ifdef HAVE_LIBLLVM_SUPPORT
annotation_options__add_disassembler(options, PERF_DISASM_LLVM);
#endif
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 1aa6df7d1618..21ac2b6472c1 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -38,6 +38,7 @@ enum perf_disassembler {
PERF_DISASM_UNKNOWN = 0,
PERF_DISASM_LLVM,
PERF_DISASM_CAPSTONE,
+ PERF_DISASM_LIBASM,
PERF_DISASM_OBJDUMP,
};
#define MAX_DISASSEMBLERS (PERF_DISASM_OBJDUMP + 1)
@@ -484,6 +485,8 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel);
void annotation_options__init(void);
void annotation_options__exit(void);
+int annotation_options__add_disassemblers_str(struct annotation_options *options,
+ const char *str);
void annotation_config__init(void);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 59ba88e1f744..42af3603fdff 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -22,6 +22,7 @@
#include "capstone.h"
#include "debug.h"
#include "disasm.h"
+#include "libasm.h"
#include "dso.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1622,6 +1623,10 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
args->options->disassembler_used = PERF_DISASM_CAPSTONE;
err = symbol__disassemble_capstone(symfs_filename, sym, args);
break;
+ case PERF_DISASM_LIBASM:
+ args->options->disassembler_used = PERF_DISASM_LIBASM;
+ err = symbol__disassemble_libasm(symfs_filename, sym, args);
+ break;
case PERF_DISASM_OBJDUMP:
args->options->disassembler_used = PERF_DISASM_OBJDUMP;
err = symbol__disassemble_objdump(symfs_filename, sym, args);
diff --git a/tools/perf/util/libasm.c b/tools/perf/util/libasm.c
new file mode 100644
index 000000000000..3f4274b1a01f
--- /dev/null
+++ b/tools/perf/util/libasm.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libasm.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <elfutils/libasm.h>
+#include <gelf.h>
+
+#include "annotate.h"
+#include "debug.h"
+#include "disasm.h"
+#include "dso.h"
+#include "map.h"
+#include "namespaces.h"
+#include "symbol.h"
+
+typedef struct ebl Ebl;
+extern Ebl *ebl_openbackend(Elf *elf);
+extern void ebl_closebackend(Ebl *ebl);
+
+struct disasm_output_arg {
+ char *buf;
+ size_t size;
+};
+
+static int disasm_output_cb(char *str, size_t len, void *arg)
+{
+ struct disasm_output_arg *oa = arg;
+ size_t to_copy = len < oa->size - 1 ? len : oa->size - 1;
+
+ memcpy(oa->buf, str, to_copy);
+ oa->buf += to_copy;
+ oa->size -= to_copy;
+ *oa->buf = '\0';
+ return 0;
+}
+
+int symbol__disassemble_libasm(const char *filename, struct symbol *sym,
+ struct annotate_args *args)
+{
+ struct annotation *notes = symbol__annotation(sym);
+ struct map *map = args->ms->map;
+ struct dso *dso = map__dso(map);
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 offset;
+ bool is_64bit = false;
+ u8 *code_buf = NULL;
+ const u8 *buf;
+ u64 buf_len;
+ Elf *elf = NULL;
+ Ebl *ebl = NULL;
+ DisasmCtx_t *handle = NULL;
+ char disasm_buf[512];
+ struct disasm_line *dl;
+ struct nscookie nsc;
+ const uint8_t *pc;
+ const uint8_t *end;
+ u64 addr;
+ size_t insn_len;
+ int ret;
+ int fd = -1;
+ int count = 0;
+
+ if (args->options->objdump_path)
+ return -1;
+
+ buf = dso__read_symbol(dso, filename, map, sym,
+ &code_buf, &buf_len, &is_64bit);
+ if (buf == NULL)
+ return errno;
+
+ /* add the function address and name */
+ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
+ start, sym->name);
+
+ args->offset = -1;
+ args->line = disasm_buf;
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms->sym = sym;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ goto err;
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (!elf)
+ goto err;
+
+ ebl = ebl_openbackend(elf);
+ if (!ebl)
+ goto err;
+
+ handle = disasm_begin(ebl, elf, NULL);
+ if (!handle)
+ goto err;
+
+ pc = buf;
+ end = buf + buf_len;
+ addr = start;
+
+ offset = 0;
+ while (pc < end) {
+ struct disasm_output_arg oa = {
+ .buf = disasm_buf,
+ .size = sizeof(disasm_buf),
+ };
+ const uint8_t *prev_pc = pc;
+
+ ret = disasm_cb(handle, &pc, end, addr, "%7m %.1o,%.2o,%.3o,%.4o,%.5o",
+ disasm_output_cb, &oa, NULL);
+ if (ret != 0 || pc == prev_pc) {
+ /* Disassembly failed or got stuck */
+ break;
+ }
+
+ args->offset = offset;
+ args->line = disasm_buf;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ insn_len = pc - prev_pc;
+ offset += insn_len;
+ addr += insn_len;
+ count++;
+ }
+
+ if (offset != buf_len) {
+ struct list_head *list = ¬es->src->source;
+
+ /* Discard all lines and fallback to objdump */
+ while (!list_empty(list)) {
+ dl = list_first_entry(list, struct disasm_line, al.node);
+
+ list_del_init(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ count = -1;
+ }
+
+out:
+ if (handle)
+ disasm_end(handle);
+ if (ebl)
+ ebl_closebackend(ebl);
+ if (elf)
+ elf_end(elf);
+ if (fd >= 0)
+ close(fd);
+ free(code_buf);
+ return count < 0 ? count : 0;
+
+err:
+ {
+ struct disasm_line *tmp;
+
+ /*
+ * It probably failed in the middle of the above loop.
+ * Release any resources it might add.
+ */
+ list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) {
+ list_del(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ }
+
+ count = -1;
+ goto out;
+}
diff --git a/tools/perf/util/libasm.h b/tools/perf/util/libasm.h
new file mode 100644
index 000000000000..d4324edf059e
--- /dev/null
+++ b/tools/perf/util/libasm.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PERF_LIBASM_H
+#define __PERF_LIBASM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+struct annotate_args;
+struct symbol;
+
+#ifdef HAVE_LIBASM_SUPPORT
+int symbol__disassemble_libasm(const char *filename, struct symbol *sym,
+ struct annotate_args *args);
+#else /* !HAVE_LIBASM_SUPPORT */
+static inline int symbol__disassemble_libasm(const char *filename __maybe_unused,
+ struct symbol *sym __maybe_unused,
+ struct annotate_args *args __maybe_unused)
+{
+ return -1;
+}
+#endif /* HAVE_LIBASM_SUPPORT */
+
+#endif /* __PERF_LIBASM_H */
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 4/7] perf annotate: Add --disassembler command-line option
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
` (2 preceding siblings ...)
2026-06-09 7:07 ` [PATCH v2 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:07 ` [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
` (3 subsequent siblings)
7 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
Add the --disassembler command-line option to perf annotate. This
allows users to explicitly request or override the disassembler
preferences (e.g. --disassembler libasm) directly on the command
line.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-annotate.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 8a0eb30eac24..57a88adfb130 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -699,6 +699,7 @@ int cmd_annotate(int argc, const char **argv)
.set = 0,
};
const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
+ const char *disassemblers_str = NULL;
struct option options[] = {
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
@@ -782,6 +783,8 @@ int cmd_annotate(int argc, const char **argv)
"Do not display empty (or dummy) events in the output"),
OPT_BOOLEAN(0, "code-with-type", &annotate_opts.code_with_type,
"Show data type info in code annotation (memory instructions only)"),
+ OPT_STRING(0, "disassembler", &disassemblers_str, "names",
+ "comma separated list of disassemblers to use"),
OPT_END()
};
int ret;
@@ -825,6 +828,13 @@ int cmd_annotate(int argc, const char **argv)
return -ENOMEM;
}
+ if (disassemblers_str) {
+ memset(annotate_opts.disassemblers, 0, sizeof(annotate_opts.disassemblers));
+ ret = annotation_options__add_disassemblers_str(&annotate_opts, disassemblers_str);
+ if (ret)
+ return -EINVAL;
+ }
+
if (annotate_check_args() < 0)
return -EINVAL;
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
` (3 preceding siblings ...)
2026-06-09 7:07 ` [PATCH v2 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:15 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
` (2 subsequent siblings)
7 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
Update the annotate.sh shell test to test different disassembler
backends (objdump, llvm, capstone, libasm) utilizing the new
--disassembler command-line option.
Isolate the test script from host environment pollution by exporting
PERF_CONFIG=/dev/null at the start of the script, ensuring it runs
hermetically.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/shell/annotate.sh | 54 ++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
index 689de58e9238..2c06d2670cb1 100755
--- a/tools/perf/tests/shell/annotate.sh
+++ b/tools/perf/tests/shell/annotate.sh
@@ -4,6 +4,8 @@
set -e
+export PERF_CONFIG=/dev/null
+
shelldir=$(dirname "$0")
# shellcheck source=lib/perf_has_symbol.sh
@@ -106,8 +108,60 @@ test_basic() {
echo "${mode} annotate test [Success]"
}
+test_disassembler() {
+ disassembler=$1
+ feature=$2
+
+ if [ -n "${feature}" ]
+ then
+ if ! perf check feature "${feature}" > /dev/null 2>&1
+ then
+ echo "Skip test for ${disassembler} (feature ${feature} not supported)"
+ return 0
+ fi
+ fi
+
+ echo "Test annotate with disassembler: ${disassembler}"
+
+ perf annotate --no-demangle -i "${perfdata}" --stdio --percent-limit 10 --disassembler "${disassembler}" 2> /dev/null > "${perfout}" || ret=$?
+
+ if [ "x${ret}" != "x0" ]
+ then
+ echo "annotate with ${disassembler} [Failed: perf annotate error]"
+ err=1
+ return 0
+ fi
+
+ # check if it has the target symbol
+ if ! grep -q "${testsym}" "${perfout}"
+ then
+ echo "annotate with ${disassembler} [Failed: missing target symbol]"
+ err=1
+ return 0
+ fi
+
+ # check if it has the disassembly lines
+ if ! grep -q "${disasm_regex}" "${perfout}"
+ then
+ echo "annotate with ${disassembler} [Failed: missing disasm output]"
+ err=1
+ return 0
+ fi
+
+ echo "annotate with ${disassembler} [Success]"
+ return 0
+}
+
test_basic Basic
test_basic Pipe
+if [ "${err}" -eq 0 ]
+then
+ test_disassembler "objdump" ""
+ test_disassembler "llvm" "libLLVM"
+ test_disassembler "capstone" "libcapstone"
+ test_disassembler "libasm" "libasm"
+fi
+
cleanup
exit $err
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
` (4 preceding siblings ...)
2026-06-09 7:07 ` [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:22 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
7 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
For in-memory BPF DSOs (DSO_BINARY_TYPE__BPF_PROG_INFO), write the
JITted instruction buffer to a temporary ELF file on disk using the
existing genelf framework (jit_write_elf). Reroute disassembly to
this temporary ELF file, allowing objdump and libasm to disassemble it
natively. Clean up the temporary file afterward.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/genelf.c | 2 +-
tools/perf/util/disasm.c | 111 +++++++++++++++++++++++++++++++++++---
tools/perf/util/disasm.h | 1 +
tools/perf/util/genelf.c | 4 +-
tools/perf/util/genelf.h | 2 +-
tools/perf/util/jitdump.c | 2 +-
6 files changed, 110 insertions(+), 12 deletions(-)
diff --git a/tools/perf/tests/genelf.c b/tools/perf/tests/genelf.c
index 95f3be1b683a..1723370db32e 100644
--- a/tools/perf/tests/genelf.c
+++ b/tools/perf/tests/genelf.c
@@ -38,7 +38,7 @@ static int test__jit_write_elf(struct test_suite *test __maybe_unused,
pr_info("Writing jit code to: %s\n", path);
- ret = jit_write_elf(fd, 0, "main", x86_code, sizeof(x86_code),
+ ret = jit_write_elf(fd, GEN_ELF_ARCH, 0, "main", x86_code, sizeof(x86_code),
NULL, 0, NULL, 0, 0);
close(fd);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 42af3603fdff..0648afd1b5f3 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -23,6 +23,9 @@
#include "debug.h"
#include "disasm.h"
#include "libasm.h"
+#ifdef HAVE_LIBELF_SUPPORT
+#include "genelf.h"
+#endif
#include "dso.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1420,7 +1423,7 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
struct child_process objdump_process;
int err;
- if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO && !args->is_temp_elf)
return symbol__disassemble_bpf_libbfd(sym, args);
if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE)
@@ -1540,6 +1543,45 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
return err;
}
+#ifdef HAVE_LIBELF_SUPPORT
+#include <unistd.h>
+#include "dwarf-regs.h"
+static int symbol__create_bpf_temp_elf(const char *filename, struct symbol *sym,
+ struct annotate_args *args,
+ char *tmp_elf, size_t tmp_elf_sz)
+{
+ struct map *map = args->ms->map;
+ struct dso *dso = map__dso(map);
+ u8 *code_buf = NULL;
+ const u8 *buf;
+ u64 buf_len;
+ bool is_64bit;
+ int tmp_fd;
+ int err = -1;
+
+ buf = dso__read_symbol(dso, filename, map, sym, &code_buf, &buf_len, &is_64bit);
+ if (!buf)
+ return -1;
+
+ snprintf(tmp_elf, tmp_elf_sz, "/tmp/perf-bpf-XXXXXX");
+ tmp_fd = mkstemp(tmp_elf);
+ if (tmp_fd >= 0) {
+ uint16_t e_machine = args->arch ? args->arch->id.e_machine : EM_HOST;
+
+ if (jit_write_elf(tmp_fd, e_machine, map__rip_2objdump(map, sym->start),
+ sym->name, buf, buf_len,
+ NULL, 0, NULL, 0, 0) == 0) {
+ err = 0;
+ }
+ close(tmp_fd);
+ if (err)
+ unlink(tmp_elf);
+ }
+ free(code_buf);
+ return err;
+}
+#endif
+
int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{
struct annotation_options *options = args->options;
@@ -1549,8 +1591,11 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
bool delete_extract = false;
struct kcore_extract kce;
bool decomp = false;
- int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
+ int err;
+
+ args->is_temp_elf = false;
+ err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
if (err)
return err;
@@ -1605,7 +1650,25 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
/* FIXME: LLVM and CAPSTONE should support source code */
if (options->annotate_src && !options->hide_src_code) {
- err = symbol__disassemble_objdump(symfs_filename, sym, args);
+ const char *disasm_filename = symfs_filename;
+ bool is_temp = false;
+ char tmp_elf[PATH_MAX];
+
+#ifdef HAVE_LIBELF_SUPPORT
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+ if (symbol__create_bpf_temp_elf(symfs_filename, sym, args,
+ tmp_elf, sizeof(tmp_elf)) == 0) {
+ disasm_filename = tmp_elf;
+ is_temp = true;
+ args->is_temp_elf = true;
+ }
+ }
+#endif
+ err = symbol__disassemble_objdump(disasm_filename, sym, args);
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
if (err == 0)
goto out_remove_tmp;
}
@@ -1613,29 +1676,63 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
err = -1;
for (u8 i = 0; i < ARRAY_SIZE(options->disassemblers) && err != 0; i++) {
enum perf_disassembler dis = options->disassemblers[i];
+ const char *disasm_filename = symfs_filename;
+ bool is_temp = false;
+ char tmp_elf[PATH_MAX];
+
+ switch (dis) {
+ case PERF_DISASM_LIBASM:
+ case PERF_DISASM_OBJDUMP:
+#ifdef HAVE_LIBELF_SUPPORT
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+ if (symbol__create_bpf_temp_elf(symfs_filename, sym, args,
+ tmp_elf, sizeof(tmp_elf)) == 0) {
+ disasm_filename = tmp_elf;
+ is_temp = true;
+ args->is_temp_elf = true;
+ }
+ }
+#endif
+ break;
+ case PERF_DISASM_LLVM:
+ case PERF_DISASM_CAPSTONE:
+ case PERF_DISASM_UNKNOWN:
+ default:
+ break;
+ }
switch (dis) {
case PERF_DISASM_LLVM:
args->options->disassembler_used = PERF_DISASM_LLVM;
- err = symbol__disassemble_llvm(symfs_filename, sym, args);
+ err = symbol__disassemble_llvm(disasm_filename, sym, args);
break;
case PERF_DISASM_CAPSTONE:
args->options->disassembler_used = PERF_DISASM_CAPSTONE;
- err = symbol__disassemble_capstone(symfs_filename, sym, args);
+ err = symbol__disassemble_capstone(disasm_filename, sym, args);
break;
case PERF_DISASM_LIBASM:
args->options->disassembler_used = PERF_DISASM_LIBASM;
- err = symbol__disassemble_libasm(symfs_filename, sym, args);
+ err = symbol__disassemble_libasm(disasm_filename, sym, args);
break;
case PERF_DISASM_OBJDUMP:
args->options->disassembler_used = PERF_DISASM_OBJDUMP;
- err = symbol__disassemble_objdump(symfs_filename, sym, args);
+ err = symbol__disassemble_objdump(disasm_filename, sym, args);
break;
case PERF_DISASM_UNKNOWN: /* End of disassemblers. */
default:
args->options->disassembler_used = PERF_DISASM_UNKNOWN;
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
goto out_remove_tmp;
}
+
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
+
if (err == 0)
pr_debug("Disassembled with %s\n", perf_disassembler__strs[dis]);
}
diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h
index 25756e3f47e4..32a5b3f5d1c6 100644
--- a/tools/perf/util/disasm.h
+++ b/tools/perf/util/disasm.h
@@ -106,6 +106,7 @@ struct annotate_args {
char *line;
int line_nr;
char *fileloc;
+ bool is_temp_elf;
};
const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid);
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index 14882def9704..42731b6de797 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -179,7 +179,7 @@ static void blake2s_update_tagged(struct blake2s_ctx *ctx, int tag,
* csize: the code size in bytes
*/
int
-jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
+jit_write_elf(int fd, uint16_t e_machine, uint64_t load_addr __maybe_unused, const char *sym,
const void *code, int csize,
void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
@@ -218,7 +218,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
- ehdr->e_machine = GEN_ELF_ARCH;
+ ehdr->e_machine = e_machine;
ehdr->e_type = ET_DYN;
ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
ehdr->e_version = EV_CURRENT;
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index 9f0b875d6548..992ca1eb2734 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -5,7 +5,7 @@
#include <linux/math.h>
/* genelf.c */
-int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
+int jit_write_elf(int fd, uint16_t e_machine, uint64_t code_addr, const char *sym,
const void *code, int csize, void *debug, int nr_debug_entries,
void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size);
#ifdef HAVE_LIBDW_SUPPORT
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 18fd84a82153..febf3e5a7851 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -95,7 +95,7 @@ jit_emit_elf(struct jit_buf_desc *jd,
return -1;
}
- ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
+ ret = jit_write_elf(fd, GEN_ELF_ARCH, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
unwinding, unwinding_header_size, unwinding_size);
close(fd);
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
` (5 preceding siblings ...)
2026-06-09 7:07 ` [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
@ 2026-06-09 7:07 ` Ian Rogers
2026-06-09 7:18 ` sashiko-bot
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
7 siblings, 1 reply; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 7:07 UTC (permalink / raw)
To: Serhei Makarov, mark, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
Adrian Hunter, James Clark, Nick Terrell, David Sterba,
Nathan Chancellor, Tomas Glozar, Blake Jones, Dmitrii Dolgov,
Alexandre Chartre, Costa Shulyupin, Yuzhuo Jing, Michael Jeanson,
Leo Yan, Tianyou Li, Zecheng Li, Rong Bao, linux-kernel,
linux-perf-users, bpf
Expand the annotate.sh shell test to verify BPF JIT disassembly.
If the test is run with sufficient privileges (root/CAP_BPF) and
captures system BPF programs, it will extract a JITted BPF program
symbol from the perf report and run perf annotate on it.
This validates the temporary ELF generation and disassembles it using
each of the supported disassembler backends (objdump, llvm, capstone,
and libasm).
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/shell/annotate.sh | 79 ++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
index 2c06d2670cb1..9719e592befd 100755
--- a/tools/perf/tests/shell/annotate.sh
+++ b/tools/perf/tests/shell/annotate.sh
@@ -163,5 +163,84 @@ then
test_disassembler "libasm" "libasm"
fi
+test_bpf_disassembler() {
+ disassembler=$1
+ feature=$2
+
+ if [ -n "${feature}" ]
+ then
+ if ! perf check feature "${feature}" > /dev/null 2>&1
+ then
+ echo "Skip BPF JIT test for ${disassembler} (feature ${feature} not supported)"
+ return 0
+ fi
+ fi
+
+ echo "Test BPF JIT annotate with disassembler: ${disassembler}"
+
+ if ! perf annotate --no-demangle -i "${perfdata}" --stdio "${bpf_sym}" \
+ --disassembler "${disassembler}" 2> /dev/null > "${perfout}"
+ then
+ echo "BPF JIT annotate with ${disassembler} [Failed: perf annotate error]"
+ err=1
+ return 0
+ fi
+
+ if ! grep -q "${disasm_regex}" "${perfout}"
+ then
+ echo "BPF JIT annotate with ${disassembler} [Failed: missing disasm output]"
+ err=1
+ return 0
+ fi
+
+ echo "BPF JIT annotate with ${disassembler} [Success]"
+ return 0
+}
+
+test_bpf() {
+ echo "Test annotate with BPF JIT output"
+
+ if ! perf check -q feature libbpf-strings ; then
+ echo "BPF annotation test [Skipped - libbpf-strings not supported]"
+ return 0
+ fi
+
+ bpftmp=$(mktemp -d /tmp/__perf_test.bpf.XXXXXX)
+ bpf_perfdata="${bpftmp}/perf.data"
+
+ if ! perf record -a -e cycles -F 4000 -o "${bpf_perfdata}" -- sleep 1 2> /dev/null
+ then
+ echo "BPF annotation test [Skipped - perf record -a failed, probably no privileges]"
+ rm -rf "${bpftmp}"
+ return 0
+ fi
+
+ bpf_sym=$(perf report --stdio -i "${bpf_perfdata}" 2>/dev/null | \
+ grep -E -o 'bpf_prog_[0-9a-f]{16}_[0-9A-Za-z_]*' | head -1)
+
+ if [ -z "${bpf_sym}" ]; then
+ echo "BPF annotation test [Skipped - no JITted BPF symbols with samples found]"
+ rm -rf "${bpftmp}"
+ return 0
+ fi
+
+ # temporarily override perfdata so test_bpf_disassembler uses the right file
+ local old_perfdata="${perfdata}"
+ perfdata="${bpf_perfdata}"
+
+ test_bpf_disassembler "objdump" ""
+ test_bpf_disassembler "llvm" "libLLVM"
+ test_bpf_disassembler "capstone" "libcapstone"
+ test_bpf_disassembler "libasm" "libasm"
+
+ perfdata="${old_perfdata}"
+ rm -rf "${bpftmp}"
+}
+
+if [ "${err}" -eq 0 ]
+then
+ test_bpf
+fi
+
cleanup
exit $err
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config
2026-06-09 7:07 ` [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
@ 2026-06-09 7:15 ` sashiko-bot
0 siblings, 0 replies; 21+ messages in thread
From: sashiko-bot @ 2026-06-09 7:15 UTC (permalink / raw)
To: Ian Rogers; +Cc: linux-perf-users, bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Uninitialized variable and incompatible data format causes `test_disassembler` to unconditionally fail.
--
commit 5f0bdfa4980785631dd9a8024ff9f43baa234caa
Author: Ian Rogers <irogers@google.com>
perf test: Enhance annotate test coverage and isolate config
This commit updates the annotate.sh test to support different disassembler
backends via the new --disassembler command-line option. It also isolates the
test script from host environment pollution by exporting PERF_CONFIG=/dev/null.
> diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
> index 689de58e92384..2c06d2670cb18 100755
> --- a/tools/perf/tests/shell/annotate.sh
> +++ b/tools/perf/tests/shell/annotate.sh
[ ... ]
> +test_disassembler() {
> + disassembler=$1
> + feature=$2
[ ... ]
> + perf annotate --no-demangle -i "${perfdata}" --stdio --percent-limit 10 --disassembler "${disassembler}" 2> /dev/null > "${perfout}" || ret=$?
> +
> + if [ "x${ret}" != "x0" ]
> + then
> + echo "annotate with ${disassembler} [Failed: perf annotate error]"
> + err=1
> + return 0
> + fi
[Severity: Medium]
Does this evaluation unconditionally fail the test when perf annotate succeeds?
If the perf annotate command is successful, the short-circuit `|| ret=$?` means
ret is skipped and never assigned. Because ret is not initialized as a local
variable at the start of test_disassembler(), it remains empty. The subsequent
check then evaluates to `[ "x" != "x0" ]`, which is always true and incorrectly
flags a success as a failure.
Additionally, will reading `${perfdata}` as a regular file here cause an issue
due to the test execution order?
> test_basic Basic
> test_basic Pipe
>
> +if [ "${err}" -eq 0 ]
> +then
> + test_disassembler "objdump" ""
The test_basic sequence runs `test_basic Pipe` immediately before executing
test_disassembler(). This overwrites `${perfdata}` with a pipe-format stream,
so attempting to read it using `-i "${perfdata}"` inside test_disassembler()
may cause perf annotate execution failures.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609070732.545416-1-irogers@google.com?part=5
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers
2026-06-09 7:07 ` [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
@ 2026-06-09 7:18 ` sashiko-bot
0 siblings, 0 replies; 21+ messages in thread
From: sashiko-bot @ 2026-06-09 7:18 UTC (permalink / raw)
To: Ian Rogers; +Cc: linux-perf-users, bpf
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] System-wide profiling of ambient BPF programs creates a race condition that can randomly fail the test.
- [Low] Signal interruption leaks the original perfdata file and the bpftmp directory due to temporary variable override.
--
commit 2a2752d1eb68187d4c05ebd5a52ce3cce359db69
Author: Ian Rogers <irogers@google.com>
Subject: perf test: Add BPF JIT annotation test coverage for all disassemblers
This commit expands the annotate.sh shell test to verify BPF JIT disassembly
using supported backends. It attempts to capture system BPF programs using
perf record, extracts a JITted BPF program symbol, and runs perf annotate
on it to validate temporary ELF generation.
> diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
> index 2c06d2670cb18..9719e592befd2 100755
> --- a/tools/perf/tests/shell/annotate.sh
> +++ b/tools/perf/tests/shell/annotate.sh
[ ... ]
> +test_bpf() {
> + echo "Test annotate with BPF JIT output"
> +
> + if ! perf check -q feature libbpf-strings ; then
> + echo "BPF annotation test [Skipped - libbpf-strings not supported]"
> + return 0
> + fi
> +
> + bpftmp=$(mktemp -d /tmp/__perf_test.bpf.XXXXXX)
> + bpf_perfdata="${bpftmp}/perf.data"
> +
> + if ! perf record -a -e cycles -F 4000 -o "${bpf_perfdata}" -- sleep 1 2> /dev/null
[Severity: Medium]
Will this probabilistic test setup cause unpredictable failures or silent skips?
By using perf record -a -- sleep 1 to capture ambient BPF programs, a race
condition occurs. If a short-lived BPF program unloads between the time the
kernel emits the KSYMBOL/BPF_EVENT and when perf record's sideband thread calls
bpf_prog_get_fd_by_id() to fetch the instructions, the JITed code won't be
saved in the perf.data file.
Later, perf report will list the BPF symbol, but perf annotate will fail
to disassemble it, causing a false test failure. Furthermore, if no ambient
BPF programs are active, the test silently skips, providing zero coverage in
most environments.
> + then
> + echo "BPF annotation test [Skipped - perf record -a failed, probably no privileges]"
> + rm -rf "${bpftmp}"
> + return 0
> + fi
[ ... ]
> + # temporarily override perfdata so test_bpf_disassembler uses the right file
> + local old_perfdata="${perfdata}"
> + perfdata="${bpf_perfdata}"
> +
> + test_bpf_disassembler "objdump" ""
> + test_bpf_disassembler "llvm" "libLLVM"
> + test_bpf_disassembler "capstone" "libcapstone"
> + test_bpf_disassembler "libasm" "libasm"
> +
> + perfdata="${old_perfdata}"
[Severity: Low]
Is it possible for the original perfdata and bpftmp directory to be leaked
if the script is interrupted during this section?
The script uses a signal trap to run the cleanup() handler, which relies on
the global perfdata variable:
cleanup() {
rm -rf "${perfdata}" "${perfout}"
...
If a signal like SIGINT occurs while perfdata is temporarily overridden,
cleanup() will only remove the inner bpf_perfdata and fail to delete the
original global perfdata file. Additionally, the new bpftmp directory is
never registered with the cleanup routine and will be left stranded in /tmp.
> + rm -rf "${bpftmp}"
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609070732.545416-1-irogers@google.com?part=7
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/7] perf build: Add build support and capability for elfutils libasm
2026-06-09 7:07 ` [PATCH v2 2/7] perf build: Add build support and capability " Ian Rogers
@ 2026-06-09 7:19 ` sashiko-bot
0 siblings, 0 replies; 21+ messages in thread
From: sashiko-bot @ 2026-06-09 7:19 UTC (permalink / raw)
To: Ian Rogers; +Cc: bpf, linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The LIBASM_DLOPEN build configuration is defined but completely lacks the corresponding C code to dynamically load the library.
- [Medium] Setting NO_LIBDW=1 fails to exclude libdw from the build, leading to unintended linkage and static build failures.
--
commit 2a3530a4ffc824890cb03d14fd777712b83cb02e
Author: Ian Rogers <irogers@google.com>
perf build: Add build support and capability for elfutils libasm
Configure perf build system to utilize the libasm feature check
(supporting both static and dynamic builds) and export the config flags.
Add "libasm" capability detection to perf check.
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index 6e7b15fab2ecc..8527d20f498f8 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
[ ... ]
> @@ -432,6 +439,7 @@ ifeq ($(feature-file-handle), 1)
> endif
>
> ifdef NO_LIBELF
> + NO_LIBASM := 1
> NO_LIBDW := 1
> NO_LIBUNWIND := 1
> NO_LIBBPF := 1
[ ... ]
> @@ -1060,6 +1068,20 @@ ifndef NO_CAPSTONE
> endif
> endif
>
> +ifndef NO_LIBASM
> + $(call feature_check,libasm)
> + ifeq ($(feature-libasm), 1)
> + CFLAGS += -DHAVE_LIBASM_SUPPORT $(LIBASM_CFLAGS)
> + ifdef LIBASM_DLOPEN
> + CFLAGS += -DLIBASM_DLOPEN
[Severity: Medium]
Is there corresponding C code to handle the dlopen and dlsym wrappers for
libasm?
It looks like if LIBASM_DLOPEN is defined, the build skips linking libasm
directly. However, without the runtime dynamic loading implementation, won't
this result in unresolved symbol linker errors when trying to build with
LIBASM_DLOPEN=1?
> + else
> + LDFLAGS += $(LIBASM_LDFLAGS)
> + EXTLIBS += -lasm -ldw -lelf
[Severity: Medium]
If a user configures the build with NO_LIBDW=1 to avoid linking libdw, won't
this unconditional addition of -ldw override their request?
Setting NO_LIBDW=1 does not implicitly set NO_LIBASM=1. As a result, the
libasm feature check still executes and forcibly appends -ldw to EXTLIBS.
For static builds, will this cause linker errors since NO_LIBDW=1 skips adding
DWARFLIBS (like -lz and -lzstd) that libdw.a requires?
> + endif
> + $(call detected,CONFIG_LIBASM)
> + endif
> +endif
> +
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609070732.545416-1-irogers@google.com?part=2
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/7] tools build: Add feature check for elfutils libasm
2026-06-09 7:07 ` [PATCH v2 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
@ 2026-06-09 7:21 ` sashiko-bot
0 siblings, 0 replies; 21+ messages in thread
From: sashiko-bot @ 2026-06-09 7:21 UTC (permalink / raw)
To: Ian Rogers; +Cc: linux-perf-users, bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The libasm feature check test relies on internal elfutils symbols (`ebl_openbackend`), guaranteeing linkage failure on all systems.
--
commit cf97b2eea73923674f23b7d737c06550cb83a7a9
Author: Ian Rogers <irogers@google.com>
tools build: Add feature check for elfutils libasm
This commit introduces a build-time feature test for the elfutils libasm
library in the shared tools/build system. It adds the test program and
updates the Makefiles to attempt building it to detect support.
> diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
> index 62909a9c799d3..f0f39a2ab2035 100644
> --- a/tools/build/feature/Makefile
> +++ b/tools/build/feature/Makefile
[ ... ]
> @@ -184,6 +185,11 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
> DWARFLIBS += -ldl
> endif
>
> +ASMLIBS := -lasm -ldw -lelf
[Severity: High]
On older systems where ebl_openbackend() was an exported symbol, it resided
in libebl.so. Since ASMLIBS omits -lebl, won't this cause linkage failures
during the test build due to missing dependencies?
> +ifeq ($(findstring -static,${LDFLAGS}),-static)
> + ASMLIBS += -lz -llzma -lbz2 -lzstd
> +endif
[ ... ]
> diff --git a/tools/build/feature/test-libasm.c b/tools/build/feature/test-libasm.c
> new file mode 100644
> index 0000000000000..f3598ad1cc9e1
> --- /dev/null
> +++ b/tools/build/feature/test-libasm.c
> @@ -0,0 +1,19 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stddef.h>
> +#include <elfutils/libasm.h>
> +#include <gelf.h>
> +
> +typedef struct ebl Ebl;
> +extern Ebl *ebl_openbackend (Elf *elf);
> +extern void ebl_closebackend (Ebl *ebl);
> +
> +int main(void)
> +{
> + Elf *elf = elf_begin(0, ELF_C_READ, NULL);
> + Ebl *ebl = ebl_openbackend(elf);
[Severity: High]
Will this test program universally fail to link?
In modern elfutils (>= 0.177), libebl was merged into libdw, and functions
like ebl_openbackend() and ebl_closebackend() were made strictly internal
with hidden visibility. They are not exported by libdw.so or libasm.so.
Because of the missing -lebl flag on older systems and the hidden visibility
on newer systems, it seems this feature check will always fail, making
any libasm disassembler backend depending on it unreachable. Is there a
different way to initialize the disassembler context without relying on
internal symbols?
> + DisasmCtx_t *ctx = disasm_begin(ebl, elf, NULL);
> + disasm_end(ctx);
> + ebl_closebackend(ebl);
> + elf_end(elf);
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609070732.545416-1-irogers@google.com?part=1
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf
2026-06-09 7:07 ` [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
@ 2026-06-09 7:22 ` sashiko-bot
0 siblings, 0 replies; 21+ messages in thread
From: sashiko-bot @ 2026-06-09 7:22 UTC (permalink / raw)
To: Ian Rogers; +Cc: bpf, linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Objdump fails to disassemble the temporary BPF ELF file because of an address range mismatch between the ELF file's hardcoded text section and objdump's `--start-address` boundary.
--
commit 515b53823b20255d2b911e2440f76dd5f76eaf39
Author: Ian Rogers <irogers@google.com>
perf annotate: Support BPF JIT disassembly via genelf
For in-memory BPF DSOs (DSO_BINARY_TYPE__BPF_PROG_INFO), write the
JITted instruction buffer to a temporary ELF file on disk using the
existing genelf framework (jit_write_elf). Reroute disassembly to
this temporary ELF file, allowing objdump and libasm to disassemble it
natively. Clean up the temporary file afterward.
> diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
> index 42af3603fdffd..0648afd1b5f31 100644
> --- a/tools/perf/util/disasm.c
> +++ b/tools/perf/util/disasm.c
[ ... ]
> +#ifdef HAVE_LIBELF_SUPPORT
> +#include <unistd.h>
> +#include "dwarf-regs.h"
> +static int symbol__create_bpf_temp_elf(const char *filename, struct symbol *sym,
> + struct annotate_args *args,
> + char *tmp_elf, size_t tmp_elf_sz)
> +{
[ ... ]
> + if (tmp_fd >= 0) {
> + uint16_t e_machine = args->arch ? args->arch->id.e_machine : EM_HOST;
> +
> + if (jit_write_elf(tmp_fd, e_machine, map__rip_2objdump(map, sym->start),
> + sym->name, buf, buf_len,
> + NULL, 0, NULL, 0, 0) == 0) {
[Severity: Medium]
Will this cause objdump to misalign or truncate the disassembly?
When symbol__create_bpf_temp_elf() calls jit_write_elf(), it passes
map__rip_2objdump(map, sym->start) as the load_addr argument, but
jit_write_elf() explicitly ignores this argument:
tools/perf/util/genelf.c:jit_write_elf() {
...
int
jit_write_elf(int fd, uint16_t e_machine, uint64_t load_addr __maybe_unused, const char *sym,
...
}
Instead, jit_write_elf() hardcodes the .text section VMA to
GEN_ELF_TEXT_OFFSET (typically 128 bytes).
Later, when symbol__disassemble_objdump() invokes objdump, it uses
--start-address and --stop-address derived from the symbol's start and end
addresses:
tools/perf/util/disasm.c:symbol__disassemble_objdump() {
...
err = asprintf(&command,
"%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64
...
}
For BPF DSOs, these addresses typically map to the range [0, csize]. However,
the actual instructions inside the generated ELF are placed at
[GEN_ELF_TEXT_OFFSET, GEN_ELF_TEXT_OFFSET + csize].
If the BPF program is smaller than GEN_ELF_TEXT_OFFSET, does objdump end up
outputting nothing? If it is larger, could this result in objdump reading
misaligned and truncated instructions that no longer match the performance
samples?
As a side note, it appears that any test added later in the series might
silently pass if it only blindly greps for offsets in objdump's output, which
would mask this offset and truncation corruption.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260609070732.545416-1-irogers@google.com?part=6
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
` (6 preceding siblings ...)
2026-06-09 7:07 ` [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
` (6 more replies)
7 siblings, 7 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
This patch series introduces support for using the elfutils `libasm` library
as a disassembler backend in `perf annotate`. This provides a lightweight,
library-based alternative to LLVM and Capstone for in-process disassembly.
Additionally, this series implements disassembly support for in-memory BPF
JITted programs by writing the JITted instruction buffer to a temporary ELF
file on the fly and disassembling it using the ELF-based backends (`objdump`
and `libasm`).
Changes in v3:
- Address review comments on v2 series.
- Explicitly link against `-lasm -ldw -lelf` in the feature check.
- Document that older versions of elfutils that require explicitly linking
`-lebl` statically are unsupported.
- Fix instruction-by-instruction disassembly loop logic in `libasm.c` by
returning 1 from output callback and checking for `ret != 1`.
- Pass the correct ELF machine (`e_machine`) to `jit_write_elf` instead of
hardcoding host architecture.
- Update `annotate.sh` tests to use `perf test -w` workload instead of `free`
to avoid CI environment issues.
- Expand test coverage to test all disassemblers (including libasm) on BPF
JIT symbols when run with root privileges.
Ian Rogers (7):
tools build: Add feature check for elfutils libasm
perf build: Add build support and capability for elfutils libasm
perf annotate: Implement elfutils libasm disassembler backend
perf annotate: Add --disassembler command-line option
perf test: Enhance annotate test coverage and isolate config
perf annotate: Support BPF JIT disassembly via genelf
perf test: Add BPF JIT annotation test coverage for all disassemblers
tools/build/Makefile.feature | 2 +
tools/build/feature/Makefile | 9 ++
tools/build/feature/test-libasm.c | 20 ++++
tools/perf/Makefile.config | 22 ++++
tools/perf/builtin-annotate.c | 10 ++
tools/perf/builtin-check.c | 1 +
tools/perf/tests/genelf.c | 2 +-
tools/perf/tests/shell/annotate.sh | 153 ++++++++++++++++++++++++
tools/perf/util/Build | 1 +
tools/perf/util/annotate.c | 8 +-
tools/perf/util/annotate.h | 3 +
tools/perf/util/disasm.c | 114 +++++++++++++++++-
tools/perf/util/disasm.h | 1 +
tools/perf/util/genelf.c | 16 +--
tools/perf/util/genelf.h | 2 +-
tools/perf/util/jitdump.c | 3 +-
tools/perf/util/libasm.c | 184 +++++++++++++++++++++++++++++
tools/perf/util/libasm.h | 27 +++++
18 files changed, 559 insertions(+), 19 deletions(-)
create mode 100644 tools/build/feature/test-libasm.c
create mode 100644 tools/perf/util/libasm.c
create mode 100644 tools/perf/util/libasm.h
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v3 1/7] tools build: Add feature check for elfutils libasm
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 2/7] perf build: Add build support and capability " Ian Rogers
` (5 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
This commit introduces a build-time feature test for the elfutils libasm
library in the shared tools/build system. It adds the test program and
updates the Makefiles to attempt building it to detect support.
Note on static linking: pkg-config for libdw/libelf on modern systems
does not list -lebl as a dependency. Older versions of elfutils that
require explicitly linking -lebl statically are unsupported by this
feature check.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/build/Makefile.feature | 2 ++
tools/build/feature/Makefile | 9 +++++++++
tools/build/feature/test-libasm.c | 20 ++++++++++++++++++++
3 files changed, 31 insertions(+)
create mode 100644 tools/build/feature/test-libasm.c
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index ed1374af31c1..422329dbc20a 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -118,6 +118,7 @@ FEATURE_TESTS_EXTRA := \
hello \
babeltrace2-ctf-writer \
libcapstone \
+ libasm \
libcheck \
libbfd-liberty \
libbfd-liberty-z \
@@ -150,6 +151,7 @@ FEATURE_DISPLAY ?= \
numa_num_possible_cpus \
libpython \
libcapstone \
+ libasm \
llvm-perf \
zlib \
lzma \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index 62909a9c799d..f0f39a2ab203 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -47,6 +47,7 @@ FILES= \
test-timerfd.bin \
test-babeltrace2-ctf-writer.bin \
test-libcapstone.bin \
+ test-libasm.bin \
test-libcheck.bin \
test-compile-32.bin \
test-compile-x32.bin \
@@ -184,6 +185,11 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
DWARFLIBS += -ldl
endif
+ASMLIBS := -lasm -ldw -lelf
+ifeq ($(findstring -static,${LDFLAGS}),-static)
+ ASMLIBS += -lz -llzma -lbz2 -lzstd
+endif
+
$(OUTPUT)test-libdw.bin:
$(BUILD) $(DWLIBS)
@@ -311,6 +317,9 @@ $(OUTPUT)test-babeltrace2-ctf-writer.bin:
$(OUTPUT)test-libcapstone.bin:
$(BUILD) # -lcapstone provided by $(FEATURE_CHECK_LDFLAGS-libcapstone)
+$(OUTPUT)test-libasm.bin:
+ $(BUILD) $(ASMLIBS)
+
$(OUTPUT)test-libcheck.bin:
$(BUILD) # -lcheck is provided by $(FEATURE_CHECK_LDFLAGS-libcheck)
diff --git a/tools/build/feature/test-libasm.c b/tools/build/feature/test-libasm.c
new file mode 100644
index 000000000000..928fc46ecc75
--- /dev/null
+++ b/tools/build/feature/test-libasm.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stddef.h>
+#include <elfutils/libasm.h>
+#include <gelf.h>
+
+struct ebl;
+extern struct ebl *ebl_openbackend(Elf *elf);
+extern void ebl_closebackend(struct ebl *ebl);
+
+int main(void)
+{
+ Elf *elf = elf_begin(0, ELF_C_READ, NULL);
+ struct ebl *ebl = ebl_openbackend(elf);
+ DisasmCtx_t *ctx = disasm_begin(ebl, elf, NULL);
+
+ disasm_end(ctx);
+ ebl_closebackend(ebl);
+ elf_end(elf);
+ return 0;
+}
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 2/7] perf build: Add build support and capability for elfutils libasm
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
2026-06-09 18:21 ` [PATCH v3 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
` (4 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
Configure perf build system to utilize the libasm feature check
(supporting both static and dynamic builds) and export the config flags.
Add "libasm" capability detection to perf check.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 22 ++++++++++++++++++++++
tools/perf/builtin-check.c | 1 +
2 files changed, 23 insertions(+)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 6e7b15fab2ec..632cb069c944 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -199,6 +199,13 @@ endif
FEATURE_CHECK_CFLAGS-libcapstone := $(LIBCAPSTONE_CFLAGS)
FEATURE_CHECK_LDFLAGS-libcapstone := $(LIBCAPSTONE_LDFLAGS) -lcapstone
+ifdef LIBASM_DIR
+ LIBASM_CFLAGS := -I$(LIBASM_DIR)/include
+ LIBASM_LDFLAGS := -L$(LIBASM_DIR)/lib
+endif
+FEATURE_CHECK_CFLAGS-libasm := $(LIBASM_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libasm := $(LIBASM_LDFLAGS) -lasm -ldw -lelf
+
ifdef LIBZSTD_DIR
LIBZSTD_CFLAGS := -I$(LIBZSTD_DIR)/lib
LIBZSTD_LDFLAGS := -L$(LIBZSTD_DIR)/lib
@@ -432,6 +439,7 @@ ifeq ($(feature-file-handle), 1)
endif
ifdef NO_LIBELF
+ NO_LIBASM := 1
NO_LIBDW := 1
NO_LIBUNWIND := 1
NO_LIBBPF := 1
@@ -1060,6 +1068,20 @@ ifndef NO_CAPSTONE
endif
endif
+ifdef NO_LIBDW
+ NO_LIBASM := 1
+endif
+
+ifndef NO_LIBASM
+ $(call feature_check,libasm)
+ ifeq ($(feature-libasm), 1)
+ CFLAGS += -DHAVE_LIBASM_SUPPORT $(LIBASM_CFLAGS)
+ LDFLAGS += $(LIBASM_LDFLAGS)
+ EXTLIBS += -lasm -ldw -lelf
+ $(call detected,CONFIG_LIBASM)
+ endif
+endif
+
ifdef EXTRA_TESTS
$(call detected,CONFIG_EXTRA_TESTS)
CFLAGS += -DHAVE_EXTRA_TESTS
diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c
index 60437650c50f..d2ffea4d9b8b 100644
--- a/tools/perf/builtin-check.c
+++ b/tools/perf/builtin-check.c
@@ -46,6 +46,7 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("babeltrace2-ctf-writer", HAVE_BABELTRACE2_CTF_WRITER_SUPPORT),
FEATURE_STATUS("libbpf-strings", HAVE_LIBBPF_STRINGS_SUPPORT),
FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT),
+ FEATURE_STATUS("libasm", HAVE_LIBASM_SUPPORT),
FEATURE_STATUS("libdw-dwarf-unwind", HAVE_LIBDW_SUPPORT),
FEATURE_STATUS("libelf", HAVE_LIBELF_SUPPORT),
FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT),
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 3/7] perf annotate: Implement elfutils libasm disassembler backend
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
2026-06-09 18:21 ` [PATCH v3 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
2026-06-09 18:21 ` [PATCH v3 2/7] perf build: Add build support and capability " Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
` (3 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
Implement the core disassembler backend in libasm.c utilizing elfutils'
libasm API. Hook the backend into perf annotate disassembler routing.
Configure libasm as the first-choice disassembler backend by default
(ahead of LLVM/capstone) when available.
Also, expose annotation_options__add_disassemblers_str to allow
custom disassembler selection.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/Build | 1 +
tools/perf/util/annotate.c | 8 +-
tools/perf/util/annotate.h | 3 +
tools/perf/util/disasm.c | 5 +
tools/perf/util/libasm.c | 184 +++++++++++++++++++++++++++++++++++++
tools/perf/util/libasm.h | 27 ++++++
6 files changed, 226 insertions(+), 2 deletions(-)
create mode 100644 tools/perf/util/libasm.c
create mode 100644 tools/perf/util/libasm.h
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b22cdc24082a..f1d5ebb2edfa 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -12,6 +12,7 @@ perf-util-y += block-range.o
perf-util-y += build-id.o
perf-util-y += cacheline.o
perf-util-$(CONFIG_LIBCAPSTONE) += capstone.o
+perf-util-$(CONFIG_LIBASM) += libasm.o
perf-util-y += config.o
perf-util-y += copyfile.o
perf-util-y += ctype.o
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 02505222d8c2..2259ac2c2cd6 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -2233,6 +2233,7 @@ const char * const perf_disassembler__strs[] = {
[PERF_DISASM_UNKNOWN] = "unknown",
[PERF_DISASM_LLVM] = "llvm",
[PERF_DISASM_CAPSTONE] = "capstone",
+ [PERF_DISASM_LIBASM] = "libasm",
[PERF_DISASM_OBJDUMP] = "objdump",
};
@@ -2254,8 +2255,8 @@ static void annotation_options__add_disassembler(struct annotation_options *opti
pr_err("Failed to add disassembler %d\n", dis);
}
-static int annotation_options__add_disassemblers_str(struct annotation_options *options,
- const char *str)
+int annotation_options__add_disassemblers_str(struct annotation_options *options,
+ const char *str)
{
while (str && *str != '\0') {
const char *comma = strchr(str, ',');
@@ -2372,6 +2373,9 @@ static void annotation_options__default_init_disassemblers(struct annotation_opt
/* Already initialized. */
return;
}
+#ifdef HAVE_LIBASM_SUPPORT
+ annotation_options__add_disassembler(options, PERF_DISASM_LIBASM);
+#endif
#ifdef HAVE_LIBLLVM_SUPPORT
annotation_options__add_disassembler(options, PERF_DISASM_LLVM);
#endif
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 1aa6df7d1618..21ac2b6472c1 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -38,6 +38,7 @@ enum perf_disassembler {
PERF_DISASM_UNKNOWN = 0,
PERF_DISASM_LLVM,
PERF_DISASM_CAPSTONE,
+ PERF_DISASM_LIBASM,
PERF_DISASM_OBJDUMP,
};
#define MAX_DISASSEMBLERS (PERF_DISASM_OBJDUMP + 1)
@@ -484,6 +485,8 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel);
void annotation_options__init(void);
void annotation_options__exit(void);
+int annotation_options__add_disassemblers_str(struct annotation_options *options,
+ const char *str);
void annotation_config__init(void);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 59ba88e1f744..42af3603fdff 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -22,6 +22,7 @@
#include "capstone.h"
#include "debug.h"
#include "disasm.h"
+#include "libasm.h"
#include "dso.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1622,6 +1623,10 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
args->options->disassembler_used = PERF_DISASM_CAPSTONE;
err = symbol__disassemble_capstone(symfs_filename, sym, args);
break;
+ case PERF_DISASM_LIBASM:
+ args->options->disassembler_used = PERF_DISASM_LIBASM;
+ err = symbol__disassemble_libasm(symfs_filename, sym, args);
+ break;
case PERF_DISASM_OBJDUMP:
args->options->disassembler_used = PERF_DISASM_OBJDUMP;
err = symbol__disassemble_objdump(symfs_filename, sym, args);
diff --git a/tools/perf/util/libasm.c b/tools/perf/util/libasm.c
new file mode 100644
index 000000000000..2f0a65733522
--- /dev/null
+++ b/tools/perf/util/libasm.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "libasm.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <elfutils/libasm.h>
+#include <gelf.h>
+
+#include "annotate.h"
+#include "debug.h"
+#include "disasm.h"
+#include "dso.h"
+#include "map.h"
+#include "namespaces.h"
+#include "symbol.h"
+
+struct ebl;
+extern struct ebl *ebl_openbackend(Elf *elf);
+extern void ebl_closebackend(struct ebl *ebl);
+
+struct disasm_output_arg {
+ char *buf;
+ size_t size;
+};
+
+static int disasm_output_cb(char *str, size_t len, void *arg)
+{
+ struct disasm_output_arg *oa = arg;
+ size_t to_copy = len < oa->size - 1 ? len : oa->size - 1;
+
+ memcpy(oa->buf, str, to_copy);
+ oa->buf += to_copy;
+ oa->size -= to_copy;
+ *oa->buf = '\0';
+ return 1;
+}
+
+int symbol__disassemble_libasm(const char *filename, struct symbol *sym,
+ struct annotate_args *args)
+{
+ struct annotation *notes = symbol__annotation(sym);
+ struct map *map = args->ms->map;
+ struct dso *dso = map__dso(map);
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 offset;
+ bool is_64bit = false;
+ u8 *code_buf = NULL;
+ const u8 *buf;
+ u64 buf_len;
+ Elf *elf = NULL;
+ struct ebl *ebl = NULL;
+ DisasmCtx_t *handle = NULL;
+ char disasm_buf[512];
+ struct disasm_line *dl;
+ struct nscookie nsc;
+ const uint8_t *pc;
+ const uint8_t *end;
+ u64 addr;
+ size_t insn_len;
+ int ret;
+ int fd = -1;
+ int count = 0;
+
+ if (args->options->objdump_path)
+ return -1;
+
+ buf = dso__read_symbol(dso, filename, map, sym,
+ &code_buf, &buf_len, &is_64bit);
+ if (buf == NULL)
+ return errno;
+
+ /* add the function address and name */
+ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
+ start, sym->name);
+
+ args->offset = -1;
+ args->line = disasm_buf;
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms->sym = sym;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ goto err;
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (!elf)
+ goto err;
+
+ ebl = ebl_openbackend(elf);
+ if (!ebl)
+ goto err;
+
+ handle = disasm_begin(ebl, elf, NULL);
+ if (!handle)
+ goto err;
+
+ pc = buf;
+ end = buf + buf_len;
+ addr = start;
+
+ offset = 0;
+ while (pc < end) {
+ struct disasm_output_arg oa = {
+ .buf = disasm_buf,
+ .size = sizeof(disasm_buf),
+ };
+ const uint8_t *prev_pc = pc;
+
+ ret = disasm_cb(handle, &pc, end, addr, "%7m %.1o,%.2o,%.3o,%.4o,%.5o",
+ disasm_output_cb, &oa, NULL);
+ if (ret != 1 || pc == prev_pc) {
+ /* Disassembly failed or got stuck */
+ break;
+ }
+
+ args->offset = offset;
+ args->line = disasm_buf;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ insn_len = pc - prev_pc;
+ offset += insn_len;
+ addr += insn_len;
+ count++;
+ }
+
+ if (offset != buf_len) {
+ struct list_head *list = ¬es->src->source;
+
+ /* Discard all lines and fallback to objdump */
+ while (!list_empty(list)) {
+ dl = list_first_entry(list, struct disasm_line, al.node);
+
+ list_del_init(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ count = -1;
+ }
+
+out:
+ if (handle)
+ disasm_end(handle);
+ if (ebl)
+ ebl_closebackend(ebl);
+ if (elf)
+ elf_end(elf);
+ if (fd >= 0)
+ close(fd);
+ free(code_buf);
+ return count < 0 ? count : 0;
+
+err:
+ {
+ struct disasm_line *tmp;
+
+ /*
+ * It probably failed in the middle of the above loop.
+ * Release any resources it might add.
+ */
+ list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) {
+ list_del(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ }
+
+ count = -1;
+ goto out;
+}
diff --git a/tools/perf/util/libasm.h b/tools/perf/util/libasm.h
new file mode 100644
index 000000000000..d4324edf059e
--- /dev/null
+++ b/tools/perf/util/libasm.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PERF_LIBASM_H
+#define __PERF_LIBASM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+struct annotate_args;
+struct symbol;
+
+#ifdef HAVE_LIBASM_SUPPORT
+int symbol__disassemble_libasm(const char *filename, struct symbol *sym,
+ struct annotate_args *args);
+#else /* !HAVE_LIBASM_SUPPORT */
+static inline int symbol__disassemble_libasm(const char *filename __maybe_unused,
+ struct symbol *sym __maybe_unused,
+ struct annotate_args *args __maybe_unused)
+{
+ return -1;
+}
+#endif /* HAVE_LIBASM_SUPPORT */
+
+#endif /* __PERF_LIBASM_H */
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 4/7] perf annotate: Add --disassembler command-line option
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
` (2 preceding siblings ...)
2026-06-09 18:21 ` [PATCH v3 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
` (2 subsequent siblings)
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
Add the --disassembler command-line option to perf annotate. This
allows users to explicitly request or override the disassembler
preferences (e.g. --disassembler libasm) directly on the command
line.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-annotate.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 8a0eb30eac24..57a88adfb130 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -699,6 +699,7 @@ int cmd_annotate(int argc, const char **argv)
.set = 0,
};
const char *disassembler_style = NULL, *objdump_path = NULL, *addr2line_path = NULL;
+ const char *disassemblers_str = NULL;
struct option options[] = {
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
@@ -782,6 +783,8 @@ int cmd_annotate(int argc, const char **argv)
"Do not display empty (or dummy) events in the output"),
OPT_BOOLEAN(0, "code-with-type", &annotate_opts.code_with_type,
"Show data type info in code annotation (memory instructions only)"),
+ OPT_STRING(0, "disassembler", &disassemblers_str, "names",
+ "comma separated list of disassemblers to use"),
OPT_END()
};
int ret;
@@ -825,6 +828,13 @@ int cmd_annotate(int argc, const char **argv)
return -ENOMEM;
}
+ if (disassemblers_str) {
+ memset(annotate_opts.disassemblers, 0, sizeof(annotate_opts.disassemblers));
+ ret = annotation_options__add_disassemblers_str(&annotate_opts, disassemblers_str);
+ if (ret)
+ return -EINVAL;
+ }
+
if (annotate_check_args() < 0)
return -EINVAL;
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 5/7] perf test: Enhance annotate test coverage and isolate config
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
` (3 preceding siblings ...)
2026-06-09 18:21 ` [PATCH v3 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
2026-06-09 18:21 ` [PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
Update the annotate.sh shell test to test different disassembler
backends (objdump, llvm, capstone, libasm) utilizing the new
--disassembler command-line option.
Isolate the test script from host environment pollution by exporting
PERF_CONFIG=/dev/null at the start of the script, ensuring it runs
hermetically.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/shell/annotate.sh | 60 ++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
index 689de58e9238..eae6a46a247b 100755
--- a/tools/perf/tests/shell/annotate.sh
+++ b/tools/perf/tests/shell/annotate.sh
@@ -4,6 +4,8 @@
set -e
+export PERF_CONFIG=/dev/null
+
shelldir=$(dirname "$0")
# shellcheck source=lib/perf_has_symbol.sh
@@ -106,8 +108,66 @@ test_basic() {
echo "${mode} annotate test [Success]"
}
+test_disassembler() {
+ disassembler=$1
+ feature=$2
+ local ret=0
+
+ if [ -n "${feature}" ]
+ then
+ if ! perf check feature "${feature}" > /dev/null 2>&1
+ then
+ echo "Skip test for ${disassembler} (feature ${feature} not supported)"
+ return 0
+ fi
+ fi
+
+ echo "Test annotate with disassembler: ${disassembler}"
+
+ perf annotate --no-demangle -i "${perfdata}" --stdio \
+ --percent-limit 10 --disassembler "${disassembler}" \
+ 2> /dev/null > "${perfout}" || ret=$?
+
+ if [ "${ret}" -ne 0 ]
+ then
+ echo "annotate with ${disassembler} [Failed: perf annotate error]"
+ err=1
+ return 0
+ fi
+
+ # check if it has the target symbol
+ if ! grep -q "${testsym}" "${perfout}"
+ then
+ echo "annotate with ${disassembler} [Failed: missing target symbol]"
+ err=1
+ return 0
+ fi
+
+ # check if it has the disassembly lines
+ if ! grep -q "${disasm_regex}" "${perfout}"
+ then
+ echo "annotate with ${disassembler} [Failed: missing disasm output]"
+ err=1
+ return 0
+ fi
+
+ echo "annotate with ${disassembler} [Success]"
+ return 0
+}
+
test_basic Basic
test_basic Pipe
+# Restore perfdata to a regular format for disassembler tests
+perf record -o "${perfdata}" ${testprog} > /dev/null 2>&1
+
+if [ "${err}" -eq 0 ]
+then
+ test_disassembler "objdump" ""
+ test_disassembler "llvm" "libLLVM"
+ test_disassembler "capstone" "libcapstone"
+ test_disassembler "libasm" "libasm"
+fi
+
cleanup
exit $err
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
` (4 preceding siblings ...)
2026-06-09 18:21 ` [PATCH v3 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
2026-06-09 18:21 ` [PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
For in-memory BPF DSOs (DSO_BINARY_TYPE__BPF_PROG_INFO), write the
JITted instruction buffer to a temporary ELF file on disk using the
existing genelf framework (jit_write_elf). Reroute disassembly to
this temporary ELF file, allowing objdump and libasm to disassemble it
natively. Clean up the temporary file afterward.
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/genelf.c | 2 +-
tools/perf/util/disasm.c | 111 +++++++++++++++++++++++++++++++++++---
tools/perf/util/disasm.h | 1 +
tools/perf/util/genelf.c | 16 +++---
tools/perf/util/genelf.h | 2 +-
tools/perf/util/jitdump.c | 3 +-
6 files changed, 117 insertions(+), 18 deletions(-)
diff --git a/tools/perf/tests/genelf.c b/tools/perf/tests/genelf.c
index 95f3be1b683a..1723370db32e 100644
--- a/tools/perf/tests/genelf.c
+++ b/tools/perf/tests/genelf.c
@@ -38,7 +38,7 @@ static int test__jit_write_elf(struct test_suite *test __maybe_unused,
pr_info("Writing jit code to: %s\n", path);
- ret = jit_write_elf(fd, 0, "main", x86_code, sizeof(x86_code),
+ ret = jit_write_elf(fd, GEN_ELF_ARCH, 0, "main", x86_code, sizeof(x86_code),
NULL, 0, NULL, 0, 0);
close(fd);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 42af3603fdff..0648afd1b5f3 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -23,6 +23,9 @@
#include "debug.h"
#include "disasm.h"
#include "libasm.h"
+#ifdef HAVE_LIBELF_SUPPORT
+#include "genelf.h"
+#endif
#include "dso.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1420,7 +1423,7 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
struct child_process objdump_process;
int err;
- if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO && !args->is_temp_elf)
return symbol__disassemble_bpf_libbfd(sym, args);
if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE)
@@ -1540,6 +1543,45 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
return err;
}
+#ifdef HAVE_LIBELF_SUPPORT
+#include <unistd.h>
+#include "dwarf-regs.h"
+static int symbol__create_bpf_temp_elf(const char *filename, struct symbol *sym,
+ struct annotate_args *args,
+ char *tmp_elf, size_t tmp_elf_sz)
+{
+ struct map *map = args->ms->map;
+ struct dso *dso = map__dso(map);
+ u8 *code_buf = NULL;
+ const u8 *buf;
+ u64 buf_len;
+ bool is_64bit;
+ int tmp_fd;
+ int err = -1;
+
+ buf = dso__read_symbol(dso, filename, map, sym, &code_buf, &buf_len, &is_64bit);
+ if (!buf)
+ return -1;
+
+ snprintf(tmp_elf, tmp_elf_sz, "/tmp/perf-bpf-XXXXXX");
+ tmp_fd = mkstemp(tmp_elf);
+ if (tmp_fd >= 0) {
+ uint16_t e_machine = args->arch ? args->arch->id.e_machine : EM_HOST;
+
+ if (jit_write_elf(tmp_fd, e_machine, map__rip_2objdump(map, sym->start),
+ sym->name, buf, buf_len,
+ NULL, 0, NULL, 0, 0) == 0) {
+ err = 0;
+ }
+ close(tmp_fd);
+ if (err)
+ unlink(tmp_elf);
+ }
+ free(code_buf);
+ return err;
+}
+#endif
+
int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{
struct annotation_options *options = args->options;
@@ -1549,8 +1591,11 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
bool delete_extract = false;
struct kcore_extract kce;
bool decomp = false;
- int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
+ int err;
+
+ args->is_temp_elf = false;
+ err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
if (err)
return err;
@@ -1605,7 +1650,25 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
/* FIXME: LLVM and CAPSTONE should support source code */
if (options->annotate_src && !options->hide_src_code) {
- err = symbol__disassemble_objdump(symfs_filename, sym, args);
+ const char *disasm_filename = symfs_filename;
+ bool is_temp = false;
+ char tmp_elf[PATH_MAX];
+
+#ifdef HAVE_LIBELF_SUPPORT
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+ if (symbol__create_bpf_temp_elf(symfs_filename, sym, args,
+ tmp_elf, sizeof(tmp_elf)) == 0) {
+ disasm_filename = tmp_elf;
+ is_temp = true;
+ args->is_temp_elf = true;
+ }
+ }
+#endif
+ err = symbol__disassemble_objdump(disasm_filename, sym, args);
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
if (err == 0)
goto out_remove_tmp;
}
@@ -1613,29 +1676,63 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
err = -1;
for (u8 i = 0; i < ARRAY_SIZE(options->disassemblers) && err != 0; i++) {
enum perf_disassembler dis = options->disassemblers[i];
+ const char *disasm_filename = symfs_filename;
+ bool is_temp = false;
+ char tmp_elf[PATH_MAX];
+
+ switch (dis) {
+ case PERF_DISASM_LIBASM:
+ case PERF_DISASM_OBJDUMP:
+#ifdef HAVE_LIBELF_SUPPORT
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+ if (symbol__create_bpf_temp_elf(symfs_filename, sym, args,
+ tmp_elf, sizeof(tmp_elf)) == 0) {
+ disasm_filename = tmp_elf;
+ is_temp = true;
+ args->is_temp_elf = true;
+ }
+ }
+#endif
+ break;
+ case PERF_DISASM_LLVM:
+ case PERF_DISASM_CAPSTONE:
+ case PERF_DISASM_UNKNOWN:
+ default:
+ break;
+ }
switch (dis) {
case PERF_DISASM_LLVM:
args->options->disassembler_used = PERF_DISASM_LLVM;
- err = symbol__disassemble_llvm(symfs_filename, sym, args);
+ err = symbol__disassemble_llvm(disasm_filename, sym, args);
break;
case PERF_DISASM_CAPSTONE:
args->options->disassembler_used = PERF_DISASM_CAPSTONE;
- err = symbol__disassemble_capstone(symfs_filename, sym, args);
+ err = symbol__disassemble_capstone(disasm_filename, sym, args);
break;
case PERF_DISASM_LIBASM:
args->options->disassembler_used = PERF_DISASM_LIBASM;
- err = symbol__disassemble_libasm(symfs_filename, sym, args);
+ err = symbol__disassemble_libasm(disasm_filename, sym, args);
break;
case PERF_DISASM_OBJDUMP:
args->options->disassembler_used = PERF_DISASM_OBJDUMP;
- err = symbol__disassemble_objdump(symfs_filename, sym, args);
+ err = symbol__disassemble_objdump(disasm_filename, sym, args);
break;
case PERF_DISASM_UNKNOWN: /* End of disassemblers. */
default:
args->options->disassembler_used = PERF_DISASM_UNKNOWN;
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
goto out_remove_tmp;
}
+
+ if (is_temp) {
+ unlink(tmp_elf);
+ args->is_temp_elf = false;
+ }
+
if (err == 0)
pr_debug("Disassembled with %s\n", perf_disassembler__strs[dis]);
}
diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h
index 25756e3f47e4..32a5b3f5d1c6 100644
--- a/tools/perf/util/disasm.h
+++ b/tools/perf/util/disasm.h
@@ -106,6 +106,7 @@ struct annotate_args {
char *line;
int line_nr;
char *fileloc;
+ bool is_temp_elf;
};
const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid);
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index 14882def9704..c3af040121ee 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -179,7 +179,7 @@ static void blake2s_update_tagged(struct blake2s_ctx *ctx, int tag,
* csize: the code size in bytes
*/
int
-jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
+jit_write_elf(int fd, uint16_t e_machine, uint64_t load_addr, const char *sym,
const void *code, int csize,
void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
@@ -218,9 +218,9 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
- ehdr->e_machine = GEN_ELF_ARCH;
+ ehdr->e_machine = e_machine;
ehdr->e_type = ET_DYN;
- ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
+ ehdr->e_entry = load_addr;
ehdr->e_version = EV_CURRENT;
ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */
@@ -230,8 +230,8 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
phdr = elf_newphdr(e, 1);
phdr[0].p_type = PT_LOAD;
phdr[0].p_offset = GEN_ELF_TEXT_OFFSET;
- phdr[0].p_vaddr = GEN_ELF_TEXT_OFFSET;
- phdr[0].p_paddr = GEN_ELF_TEXT_OFFSET;
+ phdr[0].p_vaddr = load_addr;
+ phdr[0].p_paddr = load_addr;
phdr[0].p_filesz = csize;
phdr[0].p_memsz = csize;
phdr[0].p_flags = PF_X | PF_R;
@@ -267,7 +267,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
shdr->sh_name = 1;
shdr->sh_type = SHT_PROGBITS;
- shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
+ shdr->sh_addr = load_addr;
shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
shdr->sh_entsize = 0;
@@ -278,7 +278,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
* Setup .eh_frame_hdr and .eh_frame
*/
if (unwinding) {
- eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
+ eh_frame_base_offset = ALIGN_8(load_addr + csize);
retval = jit_add_eh_frame_info(e, unwinding,
unwinding_header_size, unwinding_size,
eh_frame_base_offset);
@@ -324,7 +324,7 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
* setup symtab section
*/
symtab[1].st_size = csize;
- symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
+ symtab[1].st_value = load_addr;
scn = elf_newscn(e);
if (!scn) {
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index 9f0b875d6548..992ca1eb2734 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -5,7 +5,7 @@
#include <linux/math.h>
/* genelf.c */
-int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
+int jit_write_elf(int fd, uint16_t e_machine, uint64_t code_addr, const char *sym,
const void *code, int csize, void *debug, int nr_debug_entries,
void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size);
#ifdef HAVE_LIBDW_SUPPORT
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 18fd84a82153..ddf69032b01c 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -95,7 +95,8 @@ jit_emit_elf(struct jit_buf_desc *jd,
return -1;
}
- ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries,
+ ret = jit_write_elf(fd, GEN_ELF_ARCH, code_addr, sym,
+ (const void *)code, csize, debug, nr_debug_entries,
unwinding, unwinding_header_size, unwinding_size);
close(fd);
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
` (5 preceding siblings ...)
2026-06-09 18:21 ` [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
@ 2026-06-09 18:21 ` Ian Rogers
6 siblings, 0 replies; 21+ messages in thread
From: Ian Rogers @ 2026-06-09 18:21 UTC (permalink / raw)
To: irogers, acme, namhyung
Cc: 9erthalion6, adrian.hunter, alexandre.chartre, blakejones, bpf,
costa.shul, dsterba, james.clark, jolsa, leo.yan, linux-kernel,
linux-perf-users, mark, mingo, mjeanson, nathan, peterz, rong.bao,
serhei, terrelln, tglozar, tianyou.li, yuzhuo, zecheng
Expand the annotate.sh shell test to verify BPF JIT disassembly.
If the test is run with sufficient privileges (root/CAP_BPF) and
captures system BPF programs, it will extract a JITted BPF program
symbol from the perf report and run perf annotate on it.
This validates the temporary ELF generation and disassembles it using
each of the supported disassembler backends (objdump, llvm, capstone,
and libasm).
Assisted-by: Antigravity:Google Gemini 3.5-flash
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/shell/annotate.sh | 93 ++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh
index eae6a46a247b..ae03580fa023 100755
--- a/tools/perf/tests/shell/annotate.sh
+++ b/tools/perf/tests/shell/annotate.sh
@@ -18,6 +18,7 @@ skip_test_missing_symbol ${testsym}
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
+bpftmp=""
testprog="perf test -w noploop"
# disassembly format: "percent : offset: instruction (operands ...)"
disasm_regex="[0-9]*\.[0-9]* *: *\w*: *\w*"
@@ -25,6 +26,9 @@ disasm_regex="[0-9]*\.[0-9]* *: *\w*: *\w*"
cleanup() {
rm -rf "${perfdata}" "${perfout}"
rm -rf "${perfdata}".old
+ if [ -n "${bpftmp}" ]; then
+ rm -rf "${bpftmp}"
+ fi
trap - EXIT TERM INT
}
@@ -169,5 +173,94 @@ then
test_disassembler "libasm" "libasm"
fi
+test_bpf_disassembler() {
+ disassembler=$1
+ feature=$2
+ bpf_perfdata_file=$3
+
+ if [ -n "${feature}" ]
+ then
+ if ! perf check feature "${feature}" > /dev/null 2>&1
+ then
+ echo "Skip BPF JIT test for ${disassembler} (feature ${feature} not supported)"
+ return 0
+ fi
+ fi
+
+ echo "Test BPF JIT annotate with disassembler: ${disassembler}"
+
+ if ! perf annotate --no-demangle -i "${bpf_perfdata_file}" --stdio "${bpf_sym}" \
+ --disassembler "${disassembler}" 2> /dev/null > "${perfout}"
+ then
+ echo "BPF JIT annotate with ${disassembler} [Failed: perf annotate error]"
+ err=1
+ return 0
+ fi
+
+ if ! grep -q "${disasm_regex}" "${perfout}"
+ then
+ echo "BPF JIT annotate with ${disassembler} [Failed: missing disasm output]"
+ err=1
+ return 0
+ fi
+
+ echo "BPF JIT annotate with ${disassembler} [Success]"
+ return 0
+}
+
+test_bpf() {
+ echo "Test annotate with BPF JIT output"
+
+ if ! perf check -q feature libbpf-strings ; then
+ echo "BPF annotation test [Skipped - libbpf-strings not supported]"
+ return 0
+ fi
+
+ bpftmp=$(mktemp -d /tmp/__perf_test.bpf.XXXXXX)
+ bpf_perfdata="${bpftmp}/perf.data"
+
+ if ! perf record -a -e cycles -F 4000 -o "${bpf_perfdata}" -- sleep 1 2> /dev/null
+ then
+ echo "BPF annotation test [Skipped - perf record -a failed, probably no privileges]"
+ rm -rf "${bpftmp}"
+ bpftmp=""
+ return 0
+ fi
+
+ bpf_symbols=$(perf report --stdio -i "${bpf_perfdata}" 2>/dev/null | \
+ grep -E -o 'bpf_prog_[0-9a-f]{16}_[0-9A-Za-z_]*' | sort -u)
+
+ bpf_sym=""
+ for sym in ${bpf_symbols}
+ do
+ # Check if we can annotate it (meaning JIT code is available)
+ if perf annotate -i "${bpf_perfdata}" --stdio "${sym}" > /dev/null 2>&1
+ then
+ bpf_sym="${sym}"
+ break
+ fi
+ done
+
+ if [ -z "${bpf_sym}" ]; then
+ echo "BPF annotation test [Skipped - no JITted BPF symbols with code found (race?)]"
+ rm -rf "${bpftmp}"
+ bpftmp=""
+ return 0
+ fi
+
+ test_bpf_disassembler "objdump" "" "${bpf_perfdata}"
+ test_bpf_disassembler "llvm" "libLLVM" "${bpf_perfdata}"
+ test_bpf_disassembler "capstone" "libcapstone" "${bpf_perfdata}"
+ test_bpf_disassembler "libasm" "libasm" "${bpf_perfdata}"
+
+ rm -rf "${bpftmp}"
+ bpftmp=""
+}
+
+if [ "${err}" -eq 0 ]
+then
+ test_bpf
+fi
+
cleanup
exit $err
--
2.54.0.1099.g489fc7bff1-goog
^ permalink raw reply related [flat|nested] 21+ messages in thread
end of thread, other threads:[~2026-06-09 18:21 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-09 7:07 [PATCH v2 0/7] perf annotate: Add elfutils libasm disassembler support Ian Rogers
2026-06-09 7:07 ` [PATCH v2 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
2026-06-09 7:21 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 2/7] perf build: Add build support and capability " Ian Rogers
2026-06-09 7:19 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
2026-06-09 7:07 ` [PATCH v2 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
2026-06-09 7:07 ` [PATCH v2 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
2026-06-09 7:15 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
2026-06-09 7:22 ` sashiko-bot
2026-06-09 7:07 ` [PATCH v2 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
2026-06-09 7:18 ` sashiko-bot
2026-06-09 18:21 ` [PATCH v3 0/7] perf annotate: Add elfutils libasm disassembler and BPF JIT disassembly support Ian Rogers
2026-06-09 18:21 ` [PATCH v3 1/7] tools build: Add feature check for elfutils libasm Ian Rogers
2026-06-09 18:21 ` [PATCH v3 2/7] perf build: Add build support and capability " Ian Rogers
2026-06-09 18:21 ` [PATCH v3 3/7] perf annotate: Implement elfutils libasm disassembler backend Ian Rogers
2026-06-09 18:21 ` [PATCH v3 4/7] perf annotate: Add --disassembler command-line option Ian Rogers
2026-06-09 18:21 ` [PATCH v3 5/7] perf test: Enhance annotate test coverage and isolate config Ian Rogers
2026-06-09 18:21 ` [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf Ian Rogers
2026-06-09 18:21 ` [PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox