[PATCH v3 7/7] perf test: Add BPF JIT annotation test coverage for all disassemblers
From: Ian Rogers
Date: Tue Jun 09 2026 - 14:26:40 EST
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@xxxxxxxxxx>
---
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