bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4] bpf/scripts: Generate GCC compatible helper defs header
@ 2022-08-05  8:17 James Hilliard
  2022-08-05 15:28 ` Alexei Starovoitov
  0 siblings, 1 reply; 2+ messages in thread
From: James Hilliard @ 2022-08-05  8:17 UTC (permalink / raw)
  To: bpf
  Cc: James Hilliard, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Martin KaFai Lau, Song Liu, Yonghong Song,
	John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Nathan Chancellor, Nick Desaulniers, Tom Rix, linux-kernel, llvm

The current bpf_helper_defs.h helpers are llvm specific and don't work
correctly with gcc.

GCC requires kernel helper funcs to have the following attribute set:
__attribute__((kernel_helper(NUM)))

Generate gcc compatible headers based on the format in bpf-helpers.h.

This leaves the bpf_helper_defs.h entirely unchanged and generates a
fully separate GCC compatible bpf_helper_defs_attr.h header file
which is conditionally included if the GCC kernel_helper attribute
is supported.

This adds GCC attribute style kernel helpers in bpf_helper_defs_attr.h:
	void *bpf_map_lookup_elem(void *map, const void *key) __attribute__((kernel_helper(1)));

	long bpf_map_update_elem(void *map, const void *key, const void *value, __u64 flags) __attribute__((kernel_helper(2)));

See:
https://github.com/gcc-mirror/gcc/blob/releases/gcc-12.1.0/gcc/config/bpf/bpf-helpers.h#L24-L27

This fixes the following build error:
error: indirect call in function, which are not supported by eBPF

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
Changes v3 -> v4:
  - don't modify bpf_helper_defs.h
  - generate bpf_helper_defs_attr.h for GCC
  - check __has_attribute(kernel_helper) for selecting GCC defs
Changes v2 -> v3:
  - use a conditional helper macro
Changes v1 -> v2:
  - more details in commit log
---
 scripts/bpf_doc.py          | 58 ++++++++++++++++++++++---------------
 tools/lib/bpf/Makefile      |  7 ++++-
 tools/lib/bpf/bpf_helpers.h |  4 +++
 3 files changed, 45 insertions(+), 24 deletions(-)

diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
index dfb260de17a8..c4e8fa3619d8 100755
--- a/scripts/bpf_doc.py
+++ b/scripts/bpf_doc.py
@@ -570,9 +570,10 @@ class PrinterHelpers(Printer):
     be included from BPF program.
     @parser: A HeaderParser with Helper objects to print to standard output
     """
-    def __init__(self, parser):
+    def __init__(self, parser, attr_header):
         self.elements = parser.helpers
         self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '__BPF_FUNC_MAPPER')
+        self.attr_header = attr_header
 
     type_fwds = [
             'struct bpf_fib_lookup',
@@ -719,6 +720,24 @@ class PrinterHelpers(Printer):
 
     seen_helpers = set()
 
+    def print_args(self, proto):
+        comma = ''
+        for i, a in enumerate(proto['args']):
+            t = a['type']
+            n = a['name']
+            if proto['name'] in self.overloaded_helpers and i == 0:
+                    t = 'void'
+                    n = 'ctx'
+            one_arg = '{}{}'.format(comma, self.map_type(t))
+            if n:
+                if a['star']:
+                    one_arg += ' {}'.format(a['star'])
+                else:
+                    one_arg += ' '
+                one_arg += '{}'.format(n)
+            comma = ', '
+            print(one_arg, end='')
+
     def print_one(self, helper):
         proto = helper.proto_break_down()
 
@@ -742,26 +761,16 @@ class PrinterHelpers(Printer):
                 print(' *{}{}'.format(' \t' if line else '', line))
 
         print(' */')
-        print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
-                                      proto['ret_star'], proto['name']), end='')
-        comma = ''
-        for i, a in enumerate(proto['args']):
-            t = a['type']
-            n = a['name']
-            if proto['name'] in self.overloaded_helpers and i == 0:
-                    t = 'void'
-                    n = 'ctx'
-            one_arg = '{}{}'.format(comma, self.map_type(t))
-            if n:
-                if a['star']:
-                    one_arg += ' {}'.format(a['star'])
-                else:
-                    one_arg += ' '
-                one_arg += '{}'.format(n)
-            comma = ', '
-            print(one_arg, end='')
-
-        print(') = (void *) %d;' % len(self.seen_helpers))
+        if self.attr_header:
+            print('%s %s%s(' % (self.map_type(proto['ret_type']),
+                                          proto['ret_star'], proto['name']), end='')
+            self.print_args(proto)
+            print(') __attribute__((kernel_helper(%d)));' % len(self.seen_helpers))
+        else:
+            print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
+                                          proto['ret_star'], proto['name']), end='')
+            self.print_args(proto)
+            print(') = (void *) %d;' % len(self.seen_helpers))
         print('')
 
 ###############################################################################
@@ -785,6 +794,8 @@ rst2man utility.
 """)
 argParser.add_argument('--header', action='store_true',
                        help='generate C header file')
+argParser.add_argument('--attr-header', action='store_true',
+                       help='generate GCC attr style C header file')
 if (os.path.isfile(bpfh)):
     argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
                            default=bpfh)
@@ -799,10 +810,11 @@ headerParser = HeaderParser(args.filename)
 headerParser.run()
 
 # Print formatted output to standard output.
-if args.header:
+if args.header or args.attr_header:
     if args.target != 'helpers':
         raise NotImplementedError('Only helpers header generation is supported')
-    printer = PrinterHelpers(headerParser)
+    attr_header = True if args.attr_header else False
+    printer = PrinterHelpers(headerParser, attr_header)
 else:
     printer = printers[args.target](headerParser)
 printer.print_all()
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index 4c904ef0b47e..cf9efe764030 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -116,7 +116,8 @@ STATIC_OBJDIR	:= $(OUTPUT)staticobjs/
 BPF_IN_SHARED	:= $(SHARED_OBJDIR)libbpf-in.o
 BPF_IN_STATIC	:= $(STATIC_OBJDIR)libbpf-in.o
 BPF_HELPER_DEFS	:= $(OUTPUT)bpf_helper_defs.h
-BPF_GENERATED	:= $(BPF_HELPER_DEFS)
+BPF_HELPER_DEFS_ATTR	:= $(OUTPUT)bpf_helper_defs_attr.h
+BPF_GENERATED	:= $(BPF_HELPER_DEFS) $(BPF_HELPER_DEFS_ATTR)
 
 LIB_TARGET	:= $(addprefix $(OUTPUT),$(LIB_TARGET))
 LIB_FILE	:= $(addprefix $(OUTPUT),$(LIB_FILE))
@@ -160,6 +161,10 @@ $(BPF_HELPER_DEFS): $(srctree)/tools/include/uapi/linux/bpf.h
 	$(QUIET_GEN)$(srctree)/scripts/bpf_doc.py --header \
 		--file $(srctree)/tools/include/uapi/linux/bpf.h > $(BPF_HELPER_DEFS)
 
+$(BPF_HELPER_DEFS_ATTR): $(srctree)/tools/include/uapi/linux/bpf.h
+	$(QUIET_GEN)$(srctree)/scripts/bpf_doc.py --attr-header \
+		--file $(srctree)/tools/include/uapi/linux/bpf.h > $(BPF_HELPER_DEFS_ATTR)
+
 $(OUTPUT)libbpf.so: $(OUTPUT)libbpf.so.$(LIBBPF_VERSION)
 
 $(OUTPUT)libbpf.so.$(LIBBPF_VERSION): $(BPF_IN_SHARED) $(VERSION_SCRIPT)
diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h
index 7349b16b8e2f..b7573e7d3feb 100644
--- a/tools/lib/bpf/bpf_helpers.h
+++ b/tools/lib/bpf/bpf_helpers.h
@@ -8,7 +8,11 @@
  * in advance since bpf_helper_defs.h uses such types
  * as __u64.
  */
+#if __has_attribute(kernel_helper)
+#include "bpf_helper_defs_attr.h"
+#else
 #include "bpf_helper_defs.h"
+#endif
 
 #define __uint(name, val) int (*name)[val]
 #define __type(name, val) typeof(val) *name
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v4] bpf/scripts: Generate GCC compatible helper defs header
  2022-08-05  8:17 [PATCH v4] bpf/scripts: Generate GCC compatible helper defs header James Hilliard
@ 2022-08-05 15:28 ` Alexei Starovoitov
  0 siblings, 0 replies; 2+ messages in thread
From: Alexei Starovoitov @ 2022-08-05 15:28 UTC (permalink / raw)
  To: James Hilliard
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
	KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
	Nathan Chancellor, Nick Desaulniers, Tom Rix, LKML, llvm

On Fri, Aug 5, 2022 at 1:18 AM James Hilliard <james.hilliard1@gmail.com> wrote:
>
> The current bpf_helper_defs.h helpers are llvm specific and don't work
> correctly with gcc.
>
> GCC requires kernel helper funcs to have the following attribute set:
> __attribute__((kernel_helper(NUM)))
>
> Generate gcc compatible headers based on the format in bpf-helpers.h.
>
> This leaves the bpf_helper_defs.h entirely unchanged and generates a
> fully separate GCC compatible bpf_helper_defs_attr.h header file
> which is conditionally included if the GCC kernel_helper attribute
> is supported.
>
> This adds GCC attribute style kernel helpers in bpf_helper_defs_attr.h:
>         void *bpf_map_lookup_elem(void *map, const void *key) __attribute__((kernel_helper(1)));
>
>         long bpf_map_update_elem(void *map, const void *key, const void *value, __u64 flags) __attribute__((kernel_helper(2)));
>
> See:
> https://github.com/gcc-mirror/gcc/blob/releases/gcc-12.1.0/gcc/config/bpf/bpf-helpers.h#L24-L27
>
> This fixes the following build error:
> error: indirect call in function, which are not supported by eBPF
>
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> ---
> Changes v3 -> v4:
>   - don't modify bpf_helper_defs.h
>   - generate bpf_helper_defs_attr.h for GCC
>   - check __has_attribute(kernel_helper) for selecting GCC defs

Great job ignoring the feedback.
Applied.
Just kidding.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-08-05 15:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-05  8:17 [PATCH v4] bpf/scripts: Generate GCC compatible helper defs header James Hilliard
2022-08-05 15:28 ` Alexei Starovoitov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).