Re: [PAHOLE v5 5/5] tests: Add btf_type_tag ordering test
"Emil Tsalapatis" <[email protected]> Thu, 18 Jun 2026 00:47:30 -0400
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On Wed Jun 17, 2026 at 8:57 PM EDT, Vineet Gupta wrote: > From: Alan Maguire <[email protected]> > > Add a test that compiles a pointer carrying two btf_type_tags > (__tag(outer) __tag(inner)) and checks the BTF that pahole emits to > ensure the tag chain is PTR -> TYPE_TAG inner -> TYPE_TAG outer -> > struct sample, i.e. the innermost tag is closest to the pointer. > > This exercises the type_tag ordering for both encodings: LLVM emits the > annotations as child DIEs in source order (reversed when building the > tag list), while GCC chains them via DW_AT_GNU_annotation already in BTF > order. The test runs with gcc and clang when they support btf_type_tag, > and is skipped when bpftool is unavailable. > > Signed-off-by: Alan Maguire <[email protected]> > Signed-off-by: Vineet Gupta <[email protected]> > --- Reviewed-by: Emil Tsalapatis <[email protected]> > tests/btf_type_tag_order.sh | 179 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 179 insertions(+) > create mode 100755 tests/btf_type_tag_order.sh > > diff --git a/tests/btf_type_tag_order.sh b/tests/btf_type_tag_order.sh > new file mode 100755 > index 000000000000..09d1ac346000 > --- /dev/null > +++ b/tests/btf_type_tag_order.sh > @@ -0,0 +1,179 @@ > +#!/bin/bash > +# SPDX-License-Identifier: GPL-2.0-only > + > +# Check that pahole preserves btf_type_tag order when emitting BTF from DWARF. > + > +source test_lib.sh > + > +outdir=$(make_tmpdir) > + > +# Comment this out to save test data. > +trap cleanup EXIT > + > +title_log "Check BTF type tag order." > + > +GCC=${GCC:-gcc} > +CLANG=${CLANG:-clang} > +PAHOLE=${PAHOLE:-pahole} > +BPFTOOL=${BPFTOOL:-bpftool} > + > +if ! command -v "$BPFTOOL" > /dev/null; then > + info_log "skip: bpftool not available" > + test_skip > +fi > + > +compiler_has_btf_type_tag() > +{ > + local compiler=$1 > + > + if ! command -v "$compiler" > /dev/null; then > + return 1 > + fi > + > + "$compiler" -x c -E -P - <<'EOF' 2>/dev/null | grep -qx 1 > +#ifndef __has_attribute > +#define __has_attribute(x) 0 > +#endif > +#if __has_attribute(btf_type_tag) > +1 > +#else > +0 > +#endif > +EOF > +} > + > +use_gcc=0 > +if compiler_has_btf_type_tag "$GCC"; then > + use_gcc=1 > +fi > + > +use_clang=0 > +if compiler_has_btf_type_tag "$CLANG"; then > + use_clang=1 > +fi > + > +if [ "$use_gcc" -eq 0 ] && [ "$use_clang" -eq 0 ]; then > + error_log "Need gcc or clang with btf_type_tag support for test $0" > + test_fail > +fi > + > +src=$(cat <<EOF > +#define __tag(x) __attribute__((btf_type_tag(#x))) > + > +struct sample { > + int value; > +}; > + > +struct sample __tag(outer) __tag(inner) *global_ptr; > + > +EOF > +) > + > +check_type_tag_order() > +{ > + local btf=$1 > + local dump > + > + if ! dump=$("$BPFTOOL" btf dump file "$btf"); then > + return 1 > + fi > + > + printf '%s\n' "$dump" | awk ' > + function parse_id(line, m) { > + if (match(line, /^\[([0-9]+)\]/, m)) > + return m[1] > + return 0 > + } > + function parse_name(line, m) { > + if (match(line, /\047([^\047]*)\047/, m)) > + return m[1] > + return "" > + } > + function parse_type(line, m) { > + if (match(line, /type_id=([0-9]+)/, m)) > + return m[1] > + return 0 > + } > + function check_ptr(ptr, id, tags, seen) { > + id = type[ptr] > + while (id != 0 && !seen[id]) { > + seen[id] = 1 > + if (kind[id] == "TYPE_TAG") { > + tags = tags (tags == "" ? "" : " -> ") name[id] > + id = type[id] > + continue > + } > + if (kind[id] == "STRUCT" && name[id] == "sample") { > + if (tags == "inner -> outer") > + exit 0 > + candidates = candidates (candidates == "" ? "" : ", ") tags > + } > + return > + } > + } > + /^\[[0-9]+\]/ { > + id = parse_id($0) > + kind[id] = $2 > + name[id] = parse_name($0) > + type[id] = parse_type($0) > + if (kind[id] == "PTR") > + ptrs[++nr_ptrs] = id > + } > + END { > + for (i = 1; i <= nr_ptrs; i++) > + check_ptr(ptrs[i]) > + if (candidates != "") { > + print "type tag order mismatch; expected inner -> outer, found " candidates > "/dev/stderr" > + exit 1 > + } > + print "could not find tagged pointer to struct sample" > "/dev/stderr" > + exit 1 > + }' > +} > + > +run_test() > +{ > + local compiler=$1 > + local tmpobj=$2 > + local btf=$3 > + > + info_log "Testing with $compiler" > + > + if ! echo "$src" | "$compiler" -g -c -x c -o "$tmpobj" - 2>/dev/null; then > + error_log "Could not compile type tag order test with $compiler" > + return 1 > + fi > + > + if ! "$PAHOLE" --btf_features=+type_tag --btf_encode_detached="$btf" "$tmpobj" 2>/dev/null; then > + error_log "Could not encode BTF for $tmpobj" > + return 1 > + fi > + > + if check_type_tag_order "$btf"; then > + info_log " passed" > + return 0 > + fi > + > + error_log "BTF type tag order does not match expected order ($compiler)" > + return 1 > +} > + > +failed=0 > + > +if [ "$use_gcc" -eq 1 ]; then > + tmpobj=$(make_tmpobj) > + btf=${tmpobj%.o}.btf > + run_test "$GCC" "$tmpobj" "$btf" || failed=1 > +fi > + > +if [ "$use_clang" -eq 1 ]; then > + tmpobj=$(make_tmpobj) > + btf=${tmpobj%.o}.btf > + run_test "$CLANG" "$tmpobj" "$btf" || failed=1 > +fi > + > +if [ "$failed" -eq 0 ]; then > + test_pass > +else > + test_fail > +fi