From: Yonghong Song <yonghong.song@linux.dev>
To: Alan Maguire <alan.maguire@oracle.com>,
Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com>,
dwarves@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
bpf@vger.kernel.org, kernel-team@fb.com
Subject: [PATCH dwarves v8 5/5] tests: Add BTF true_signature encoding tests
Date: Tue, 23 Jun 2026 15:29:16 -0700 [thread overview]
Message-ID: <20260623222916.3295475-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260623222850.3290612-1-yonghong.song@linux.dev>
Add five tests exercising true_signature BTF encoding for clang-built
functions:
- clang_parm_optimized: an unused scalar parameter is dropped from the
true signature.
- clang_parm_optimized_stack: with more arguments than argument registers,
optimized-out parameters (including stack-passed ones) are dropped.
- clang_parm_aggregate_1: a two-register aggregate that is only partially
used is rewritten to its single used member, while a fully-used
aggregate is preserved.
- clang_parm_aggregate_2: like aggregate_1 but with an extra unused scalar
parameter; additionally checks (on aarch64) that the first argument name
is preserved.
- clang_parm_memory: a large aggregate classified MEMORY and passed on the
stack is kept while an unused parameter is dropped. A union is used so
the struct-parameter exception in cu__resolve_func_ret_types_optimized()
does not mask a wrong unexpected_reg.
The per-arch handling differs between the tests:
- clang_parm_optimized and clang_parm_optimized_stack assert the
signatures differ between BTF and dwarf signature.
- clang_parm_aggregate_1 asserts the signatures differ between x86_64
and aarch64. For aarch64, final signature is the same as dwarf.
- clang_parm_aggregate_2 asserts the signatures differ between x86_64
and aarch64. For aarch64, final signature is different from dwarf.
- clang_parm_memory asserts a true signature is produced with
a used big struct argument.
The following is an example to dump BTF vs. Dwarf:
$ VERBOSE=1 ./clang_parm_memory.sh
Validation of BTF encoding of true_signatures.
BTF: long foo(union big u, int x); DWARF: long foo(union big u, int dead, int x);
Test ./clang_parm_memory.sh passed
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
tests/clang_parm_aggregate_1.sh | 85 ++++++++++++++++++++++++++++
tests/clang_parm_aggregate_2.sh | 88 +++++++++++++++++++++++++++++
tests/clang_parm_memory.sh | 77 +++++++++++++++++++++++++
tests/clang_parm_optimized.sh | 63 +++++++++++++++++++++
tests/clang_parm_optimized_stack.sh | 63 +++++++++++++++++++++
5 files changed, 376 insertions(+)
create mode 100755 tests/clang_parm_aggregate_1.sh
create mode 100755 tests/clang_parm_aggregate_2.sh
create mode 100755 tests/clang_parm_memory.sh
create mode 100755 tests/clang_parm_optimized.sh
create mode 100755 tests/clang_parm_optimized_stack.sh
diff --git a/tests/clang_parm_aggregate_1.sh b/tests/clang_parm_aggregate_1.sh
new file mode 100755
index 0000000..9502f8b
--- /dev/null
+++ b/tests/clang_parm_aggregate_1.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source test_lib.sh
+
+outdir=$(make_tmpdir)
+
+# Comment this out to save test data.
+trap cleanup EXIT
+
+title_log "Validation of BTF encoding of true_signatures."
+
+clang_true="${outdir}/clang_true"
+CC=$(which clang 2>/dev/null)
+
+if [[ -z "$CC" ]]; then
+ info_log "skip: clang not available"
+ test_skip
+fi
+
+cat > ${clang_true}.c << EOF
+struct t { long f1; long f2; };
+__attribute__((noinline)) static long foo(struct t a, struct t b, int i)
+{
+ return a.f1 + b.f1 + b.f2 + i;
+}
+
+struct t p1, p2;
+int i;
+int main()
+{
+ return (int)foo(p1, p2, i);
+}
+EOF
+
+CFLAGS="$CFLAGS -g -O2"
+${CC} ${CFLAGS} -o $clang_true ${clang_true}.c
+if [[ $? -ne 0 ]]; then
+ error_log "Could not compile ${clang_true}.c"
+ test_fail
+fi
+LLVM_OBJCOPY=objcopy pahole -J --btf_features=+true_signature $clang_true
+if [[ $? -ne 0 ]]; then
+ error_log "Could not encode BTF for $clang_true"
+ test_fail
+fi
+
+btf_optimized=$(pfunct --all --format_path=btf $clang_true |grep "foo")
+if [[ -z "$btf_optimized" ]]; then
+ info_log "skip: no optimizations applied."
+ test_skip
+fi
+
+btf_cmp=$btf_optimized
+dwarf=$(pfunct --all $clang_true |grep "foo")
+
+verbose_log "BTF: $btf_optimized DWARF: $dwarf"
+
+arch=$(uname -m)
+
+if [[ "$arch" == "x86_64" ]]; then
+ # On x86_64, clang emits DW_CC_nocall for optimized functions,
+ # so pahole should detect the optimization and produce a
+ # different BTF signature.
+ if [[ "$btf_cmp" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+elif [[ "$arch" == "aarch64" ]]; then
+ # On arm64, clang does not emit DW_CC_nocall, so pahole cannot
+ # detect the optimization. BTF and DWARF signatures are expected
+ # to be the same.
+ if [[ "$btf_cmp" != "$dwarf" ]]; then
+ error_log "On arm64, BTF and DWARF signatures should be the same but they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+else
+ # On other architectures, skip if we cannot determine the
+ # expected behavior.
+ if [[ "$btf_cmp" == "$dwarf" ]]; then
+ info_log "skip: no optimization detected on $arch"
+ test_skip
+ fi
+fi
+test_pass
diff --git a/tests/clang_parm_aggregate_2.sh b/tests/clang_parm_aggregate_2.sh
new file mode 100755
index 0000000..ae03369
--- /dev/null
+++ b/tests/clang_parm_aggregate_2.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source test_lib.sh
+
+outdir=$(make_tmpdir)
+
+# Comment this out to save test data.
+trap cleanup EXIT
+
+title_log "Validation of BTF encoding of true_signatures."
+
+clang_true="${outdir}/clang_true"
+CC=$(which clang 2>/dev/null)
+
+if [[ -z "$CC" ]]; then
+ info_log "skip: clang not available"
+ test_skip
+fi
+
+cat > ${clang_true}.c << EOF
+struct t { long f1; long f2; };
+__attribute__((noinline)) static long foo(struct t a, struct t b, int i, int j)
+{
+ return a.f1 + b.f1 + b.f2 + i;
+}
+
+struct t p1, p2;
+int i;
+int main()
+{
+ return (int)foo(p1, p2, i, i + 1);
+}
+EOF
+
+CFLAGS="$CFLAGS -g -O2"
+${CC} ${CFLAGS} -o $clang_true ${clang_true}.c
+if [[ $? -ne 0 ]]; then
+ error_log "Could not compile ${clang_true}.c"
+ test_fail
+fi
+LLVM_OBJCOPY=objcopy pahole -J --btf_features=+true_signature $clang_true
+if [[ $? -ne 0 ]]; then
+ error_log "Could not encode BTF for $clang_true"
+ test_fail
+fi
+
+btf_optimized=$(pfunct --all --format_path=btf $clang_true |grep "foo")
+if [[ -z "$btf_optimized" ]]; then
+ info_log "skip: no optimizations applied."
+ test_skip
+fi
+
+btf_cmp=$btf_optimized
+dwarf=$(pfunct --all $clang_true |grep "foo")
+
+verbose_log "BTF: $btf_optimized DWARF: $dwarf"
+
+arch=$(uname -m)
+
+if [[ "$arch" == "x86_64" ]]; then
+ # On x86_64, clang emits DW_CC_nocall for optimized functions (dead code elimination),
+ # so pahole should detect the optimization and produce a different BTF signature.
+ if [[ "$btf_cmp" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+elif [[ "$arch" == "aarch64" ]]; then
+ # On arm64, clang emits DW_CC_nocall for optimized functions (dead code elimination),
+ # so pahole should detect the optimization and produce a different BTF signature.
+ if [[ "$btf_cmp" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+
+ if [[ "$btf_cmp" == *"__"* ]]; then
+ error_log "The first argument name a should be preserved and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+else
+ # On other architectures, skip if we cannot determine the
+ # expected behavior.
+ if [[ "$btf_cmp" == "$dwarf" ]]; then
+ info_log "skip: no optimization detected on $arch"
+ test_skip
+ fi
+fi
+test_pass
diff --git a/tests/clang_parm_memory.sh b/tests/clang_parm_memory.sh
new file mode 100755
index 0000000..d0d798d
--- /dev/null
+++ b/tests/clang_parm_memory.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source test_lib.sh
+
+outdir=$(make_tmpdir)
+
+# Comment this out to save test data.
+trap cleanup EXIT
+
+title_log "Validation of BTF encoding of true_signatures."
+
+clang_true="${outdir}/clang_true"
+CC=$(which clang 2>/dev/null)
+
+if [[ -z "$CC" ]]; then
+ info_log "skip: clang not available"
+ test_skip
+fi
+
+# the expected true signature: long foo(union big u, int x).
+cat > ${clang_true}.c << EOF
+union big { long a; char buf[24]; };
+__attribute__((noinline)) static long foo(union big u, int dead, int x)
+{
+ return u.a + x;
+}
+
+union big g;
+int dead, x;
+int main()
+{
+ return (int)foo(g, dead, x);
+}
+EOF
+
+CFLAGS="$CFLAGS -g -O2"
+${CC} ${CFLAGS} -o $clang_true ${clang_true}.c
+if [[ $? -ne 0 ]]; then
+ error_log "Could not compile ${clang_true}.c"
+ test_fail
+fi
+LLVM_OBJCOPY=objcopy pahole -J --btf_features=+true_signature $clang_true
+if [[ $? -ne 0 ]]; then
+ error_log "Could not encode BTF for $clang_true"
+ test_fail
+fi
+
+btf_optimized=$(pfunct --all --format_path=btf $clang_true |grep "foo")
+dwarf=$(pfunct --all $clang_true |grep "foo")
+
+verbose_log "BTF: $btf_optimized DWARF: $dwarf"
+
+arch=$(uname -m)
+
+if [[ "$arch" == "x86_64" ]]; then
+ # On x86_64, clang emits DW_CC_nocall for optimized functions. The
+ # stack-passed aggregate must remain present and 'dead' must be
+ # dropped, so a true signature must be produced and it must differ
+ # from the DWARF signature.
+ if [[ -z "$btf_optimized" ]]; then
+ error_log "BTF for foo missing; the stack-passed aggregate was likely rejected"
+ test_fail
+ fi
+ if [[ "$btf_optimized" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+ fi
+else
+ # On other architectures clang may not emit DW_CC_nocall, so we
+ # cannot assert the optimization was detected.
+ if [[ -z "$btf_optimized" ]]; then
+ info_log "skip: no optimization detected on $arch"
+ test_skip
+ fi
+fi
+test_pass
diff --git a/tests/clang_parm_optimized.sh b/tests/clang_parm_optimized.sh
new file mode 100755
index 0000000..81d50af
--- /dev/null
+++ b/tests/clang_parm_optimized.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source test_lib.sh
+
+outdir=$(make_tmpdir)
+
+# Comment this out to save test data.
+trap cleanup EXIT
+
+title_log "Validation of BTF encoding of true_signatures."
+
+clang_true="${outdir}/clang_true"
+CC=$(which clang 2>/dev/null)
+
+if [[ -z "$CC" ]]; then
+ info_log "skip: clang not available"
+ test_skip
+fi
+
+cat > ${clang_true}.c << EOF
+__attribute__((noinline)) static int foo(int a, int b, int c)
+{
+ return a * c - a - c;
+}
+
+int a, b, c;
+int main()
+{
+ return foo(a, b, c);
+}
+EOF
+
+CFLAGS="$CFLAGS -g -O2"
+${CC} ${CFLAGS} -o $clang_true ${clang_true}.c
+if [[ $? -ne 0 ]]; then
+ error_log "Could not compile ${clang_true}.c"
+ test_fail
+fi
+LLVM_OBJCOPY=objcopy pahole -J --btf_features=+true_signature $clang_true
+if [[ $? -ne 0 ]]; then
+ error_log "Could not encode BTF for $clang_true"
+ test_fail
+fi
+
+btf_optimized=$(pfunct --all --format_path=btf $clang_true |grep "foo")
+if [[ -z "$btf_optimized" ]]; then
+ info_log "skip: no optimizations applied."
+ test_skip
+fi
+
+btf_cmp=$btf_optimized
+dwarf=$(pfunct --all $clang_true |grep "foo")
+
+if [[ -n "$VERBOSE" ]]; then
+ printf " BTF: %s DWARF: %s\n" "$btf_optimized" "$dwarf"
+fi
+
+if [[ "$btf_cmp" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+fi
+test_pass
diff --git a/tests/clang_parm_optimized_stack.sh b/tests/clang_parm_optimized_stack.sh
new file mode 100755
index 0000000..afdc355
--- /dev/null
+++ b/tests/clang_parm_optimized_stack.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source test_lib.sh
+
+outdir=$(make_tmpdir)
+
+# Comment this out to save test data.
+trap cleanup EXIT
+
+title_log "Validation of BTF encoding of true_signatures."
+
+clang_true="${outdir}/clang_true"
+CC=$(which clang 2>/dev/null)
+
+if [[ -z "$CC" ]]; then
+ info_log "skip: clang not available"
+ test_skip
+fi
+
+cat > ${clang_true}.c << EOF
+__attribute__((noinline)) static int foo(int a, int b, int c, int d, int e, int f, int g, int h, int i)
+{
+ return a * i - a - i;
+}
+
+int a, b, c, d, e, f, g, h, i;
+int main()
+{
+ return foo(a, b, c, d, e, f, g, h, i);
+}
+EOF
+
+CFLAGS="$CFLAGS -g -O2"
+${CC} ${CFLAGS} -o $clang_true ${clang_true}.c
+if [[ $? -ne 0 ]]; then
+ error_log "Could not compile ${clang_true}.c"
+ test_fail
+fi
+LLVM_OBJCOPY=objcopy pahole -J --btf_features=+true_signature $clang_true
+if [[ $? -ne 0 ]]; then
+ error_log "Could not encode BTF for $clang_true"
+ test_fail
+fi
+
+btf_optimized=$(pfunct --all --format_path=btf $clang_true |grep "foo")
+if [[ -z "$btf_optimized" ]]; then
+ info_log "skip: no optimizations applied."
+ test_skip
+fi
+
+btf_cmp=$btf_optimized
+dwarf=$(pfunct --all $clang_true |grep "foo")
+
+if [[ -n "$VERBOSE" ]]; then
+ printf " BTF: %s DWARF: %s\n" "$btf_optimized" "$dwarf"
+fi
+
+if [[ "$btf_cmp" == "$dwarf" ]]; then
+ error_log "BTF and DWARF signatures should be different and they are not: BTF: $btf_optimized ; DWARF $dwarf"
+ test_fail
+fi
+test_pass
--
2.53.0-Meta
prev parent reply other threads:[~2026-06-23 22:29 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 22:28 [PATCH dwarves v8 0/5] pahole: Encode true signatures in kernel BTF Yonghong Song
2026-06-23 22:28 ` [PATCH dwarves v8 1/5] dwarf_loader: Detect aggregate ABI register usage and clang compiler Yonghong Song
2026-06-23 22:29 ` [PATCH dwarves v8 2/5] dwarf_loader: Collect per-parameter information Yonghong Song
2026-06-23 22:29 ` [PATCH dwarves v8 3/5] dwarf_loader: Analyze per-parameter information for true signatures Yonghong Song
2026-06-24 1:21 ` Yonghong Song
2026-06-23 22:29 ` [PATCH dwarves v8 4/5] btf_encoder: Emit true function signatures Yonghong Song
2026-06-24 1:45 ` Yonghong Song
2026-06-23 22:29 ` Yonghong Song [this message]
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=20260623222916.3295475-1-yonghong.song@linux.dev \
--to=yonghong.song@linux.dev \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=arnaldo.melo@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=kernel-team@fb.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