libbpf: Fix no-args func prototype BTF dumping syntax
authorAndrii Nakryiko <andrii@kernel.org>
Fri, 12 Jul 2024 22:44:42 +0000 (15:44 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Wed, 17 Jul 2024 20:42:47 +0000 (22:42 +0200)
For all these years libbpf's BTF dumper has been emitting not strictly
valid syntax for function prototypes that have no input arguments.

Instead of `int (*blah)()` we should emit `int (*blah)(void)`.

This is not normally a problem, but it manifests when we get kfuncs in
vmlinux.h that have no input arguments. Due to compiler internal
specifics, we get no BTF information for such kfuncs, if they are not
declared with proper `(void)`.

The fix is trivial. We also need to adjust a few ancient tests that
happily assumed `()` is correct.

Fixes: 351131b51c7a ("libbpf: add btf_dump API for BTF-to-C conversion")
Reported-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://lore.kernel.org/bpf/20240712224442.282823-1-andrii@kernel.org
tools/lib/bpf/btf_dump.c
tools/testing/selftests/bpf/progs/btf_dump_test_case_multidim.c
tools/testing/selftests/bpf/progs/btf_dump_test_case_syntax.c

index 5dbca76b953f46e1ecdbd2e4de91ffdb733a71c5..894860111ddb291fdd29c57c77ba2a381665dc48 100644 (file)
@@ -1559,10 +1559,12 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                         * Clang for BPF target generates func_proto with no
                         * args as a func_proto with a single void arg (e.g.,
                         * `int (*f)(void)` vs just `int (*f)()`). We are
-                        * going to pretend there are no args for such case.
+                        * going to emit valid empty args (void) syntax for
+                        * such case. Similarly and conveniently, valid
+                        * no args case can be special-cased here as well.
                         */
-                       if (vlen == 1 && p->type == 0) {
-                               btf_dump_printf(d, ")");
+                       if (vlen == 0 || (vlen == 1 && p->type == 0)) {
+                               btf_dump_printf(d, "void)");
                                return;
                        }
 
index ba97165bdb282205e34d8743a5001d128115641f..a657651eba523e0a9f0d475eaf3572a2a71607a0 100644 (file)
@@ -14,9 +14,9 @@ typedef int *ptr_arr_t[6];
 
 typedef int *ptr_multiarr_t[7][8][9][10];
 
-typedef int * (*fn_ptr_arr_t[11])();
+typedef int * (*fn_ptr_arr_t[11])(void);
 
-typedef int * (*fn_ptr_multiarr_t[12][13])();
+typedef int * (*fn_ptr_multiarr_t[12][13])(void);
 
 struct root_struct {
        arr_t _1;
index ad21ee8c7e23456a2e494f9273864affa5683156..29d01fff32bd22accb56c579f09fade05ceba7fa 100644 (file)
@@ -100,7 +100,7 @@ typedef void (*printf_fn_t)(const char *, ...);
  *   `int -> char *` function and returns pointer to a char. Equivalent:
  *   typedef char * (*fn_input_t)(int);
  *   typedef char * (*fn_output_outer_t)(fn_input_t);
- *   typedef const fn_output_outer_t (* fn_output_inner_t)();
+ *   typedef const fn_output_outer_t (* fn_output_inner_t)(void);
  *   typedef const fn_output_inner_t fn_ptr_arr2_t[5];
  */
 /* ----- START-EXPECTED-OUTPUT ----- */
@@ -127,7 +127,7 @@ typedef void (* (*signal_t)(int, void (*)(int)))(int);
 
 typedef char * (*fn_ptr_arr1_t[10])(int **);
 
-typedef char * (* (* const fn_ptr_arr2_t[5])())(char * (*)(int));
+typedef char * (* (* const fn_ptr_arr2_t[5])(void))(char * (*)(int));
 
 struct struct_w_typedefs {
        int_t a;