Re: [PAHOLE v5 5/5] tests: Add btf_type_tag ordering test
Arnaldo Carvalho de Melo <[email protected]> Thu, 18 Jun 2026 10:25:49 -0300
| Newsgroups | org.kernel.vger.dwarves,org.kernel.vger.bpf |
|---|---|
| Message-ID | <ajPx3Y-LVhwN0jM4@x1> |
On Thu, Jun 18, 2026 at 12:47:30AM -0400, Emil Tsalapatis wrote: > 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]> Acked-by: Arnaldo Carvalho de Melo <[email protected]> - Arnaldo > > 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