From: Ian Rogers <irogers@google.com>
To: irogers@google.com, acme@kernel.org, namhyung@kernel.org
Cc: 9erthalion6@gmail.com, adrian.hunter@intel.com,
alexandre.chartre@oracle.com, blakejones@google.com,
bpf@vger.kernel.org, costa.shul@redhat.com, dsterba@suse.com,
james.clark@linaro.org, jolsa@kernel.org, leo.yan@arm.com,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
mark@klomp.org, mingo@redhat.com, mjeanson@efficios.com,
nathan@kernel.org, peterz@infradead.org, rong.bao@csmantle.top,
serhei@serhei.io, terrelln@fb.com, tglozar@redhat.com,
tianyou.li@intel.com, yuzhuo@google.com, zecheng@google.com
Subject: [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf
Date: Tue, 9 Jun 2026 11:21:07 -0700 [thread overview]
Message-ID: <20260609182108.975586-7-irogers@google.com> (raw)
In-Reply-To: <20260609182108.975586-1-irogers@google.com>
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
next prev parent reply other threads:[~2026-06-09 18:21 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
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:46 ` sashiko-bot
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:52 ` sashiko-bot
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:46 ` sashiko-bot
2026-06-09 18:21 ` Ian Rogers [this message]
2026-06-09 18:49 ` [PATCH v3 6/7] perf annotate: Support BPF JIT disassembly via genelf sashiko-bot
2026-06-09 18:21 ` [PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260609182108.975586-7-irogers@google.com \
--to=irogers@google.com \
--cc=9erthalion6@gmail.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexandre.chartre@oracle.com \
--cc=blakejones@google.com \
--cc=bpf@vger.kernel.org \
--cc=costa.shul@redhat.com \
--cc=dsterba@suse.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=leo.yan@arm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark@klomp.org \
--cc=mingo@redhat.com \
--cc=mjeanson@efficios.com \
--cc=namhyung@kernel.org \
--cc=nathan@kernel.org \
--cc=peterz@infradead.org \
--cc=rong.bao@csmantle.top \
--cc=serhei@serhei.io \
--cc=terrelln@fb.com \
--cc=tglozar@redhat.com \
--cc=tianyou.li@intel.com \
--cc=yuzhuo@google.com \
--cc=zecheng@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox