<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux-toradex.git/tools/testing/selftests/bpf/progs/unwind_cxx.cpp, branch master</title>
<subtitle>Linux kernel for Apalis and Colibri modules</subtitle>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/'/>
<entry>
<title>selftests/bpf: Test unwinding from R0: R2 subprog</title>
<updated>2026-10-20T20:54:25+00:00</updated>
<author>
<name>Kumar Kartikeya Dwivedi</name>
<email>memxor@gmail.com</email>
</author>
<published>2026-10-20T18:13:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=55c34496ee99f5f41cf329c495dd111802244146'/>
<id>55c34496ee99f5f41cf329c495dd111802244146</id>
<content type='text'>
Global subprograms returning a 16-byte scalar use R0:R2. The
verifier therefore checks both registers at every ordinary and unwind
exit.

LLVM lowers a resume to "r0 = 0; unwind_exit". If cleanup code does not
happen to initialize R2, the verifier rejects the unwind path with:

  R2 !read_ok

Extend unwind_cxx with a global unsigned __int128-returning subprogram
whose cleanup only releases its RCU read lock. Load it separately so
the existing cases continue to run and the failure is attributed to
this case. Check both the normal aggregate return and caught exception.
The test passes once LLVM defines R2 before emitting unwind_exit.

Signed-off-by: Kumar Kartikeya Dwivedi &lt;memxor@gmail.com&gt;
Signed-off-by: Alexei Starovoitov &lt;ast@kernel.org&gt;
Link: https://patch.msgid.link/20261020181320.1284798-7-alexei.starovoitov@gmail.com
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Global subprograms returning a 16-byte scalar use R0:R2. The
verifier therefore checks both registers at every ordinary and unwind
exit.

LLVM lowers a resume to "r0 = 0; unwind_exit". If cleanup code does not
happen to initialize R2, the verifier rejects the unwind path with:

  R2 !read_ok

Extend unwind_cxx with a global unsigned __int128-returning subprogram
whose cleanup only releases its RCU read lock. Load it separately so
the existing cases continue to run and the failure is attributed to
this case. Check both the normal aggregate return and caught exception.
The test passes once LLVM defines R2 before emitting unwind_exit.

Signed-off-by: Kumar Kartikeya Dwivedi &lt;memxor@gmail.com&gt;
Signed-off-by: Alexei Starovoitov &lt;ast@kernel.org&gt;
Link: https://patch.msgid.link/20261020181320.1284798-7-alexei.starovoitov@gmail.com
</pre>
</div>
</content>
</entry>
<entry>
<title>selftests/bpf: Add a C++ prog with exceptions</title>
<updated>2026-10-20T20:54:25+00:00</updated>
<author>
<name>Alexei Starovoitov</name>
<email>ast@kernel.org</email>
</author>
<published>2026-10-20T18:13:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=0935acd1a8a77865e69cd9a38495daf68d769eee'/>
<id>0935acd1a8a77865e69cd9a38495daf68d769eee</id>
<content type='text'>
  static __noinline int inner(int len)
  {
          rcu_guard guard;

          if (len &gt; 100)
                  throw 1;
          return len;
  }

  static __noinline int middle(int len)
  {
          preempt_guard guard;

          return inner(len) + 1;
  }

  SEC("tc") int catches(struct __sk_buff *skb)
  {
          try {
                  return middle(skb-&gt;len);
          } catch (...) {
                  return 42;
          }
  }

The exception passes through two frames. The destructors call
bpf_rcu_read_unlock() and bpf_preempt_enable(). The verifier insists on
both, and the test checks that they ran in that order.
In the second prog nobody catches. The destructors run and the prog
returns 0.

All that is left of the C++ runtime is four one line functions.
__cxa_throw() calls _Unwind_RaiseException(), which llvm lowers.

progs/*.cpp are built like progs/*.rs: by clang only and without skeletons.
vmlinux.h and bpf_helpers.h are not C++, so the prog declares what it
needs.

clang that lowers unwinding [1] defines __BPF_FEATURE_UNWIND. Without it
the object has no progs and the test is skipped.

[1] https://github.com/llvm/llvm-project/pull/233649

Signed-off-by: Alexei Starovoitov &lt;ast@kernel.org&gt;
Link: https://patch.msgid.link/20261020181320.1284798-6-alexei.starovoitov@gmail.com
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
  static __noinline int inner(int len)
  {
          rcu_guard guard;

          if (len &gt; 100)
                  throw 1;
          return len;
  }

  static __noinline int middle(int len)
  {
          preempt_guard guard;

          return inner(len) + 1;
  }

  SEC("tc") int catches(struct __sk_buff *skb)
  {
          try {
                  return middle(skb-&gt;len);
          } catch (...) {
                  return 42;
          }
  }

The exception passes through two frames. The destructors call
bpf_rcu_read_unlock() and bpf_preempt_enable(). The verifier insists on
both, and the test checks that they ran in that order.
In the second prog nobody catches. The destructors run and the prog
returns 0.

All that is left of the C++ runtime is four one line functions.
__cxa_throw() calls _Unwind_RaiseException(), which llvm lowers.

progs/*.cpp are built like progs/*.rs: by clang only and without skeletons.
vmlinux.h and bpf_helpers.h are not C++, so the prog declares what it
needs.

clang that lowers unwinding [1] defines __BPF_FEATURE_UNWIND. Without it
the object has no progs and the test is skipped.

[1] https://github.com/llvm/llvm-project/pull/233649

Signed-off-by: Alexei Starovoitov &lt;ast@kernel.org&gt;
Link: https://patch.msgid.link/20261020181320.1284798-6-alexei.starovoitov@gmail.com
</pre>
</div>
</content>
</entry>
</feed>
