mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
bpf: Allow specifying bpf_fastcall attribute for BPF helpers
Allow a new optional 'Attributes' section to be specified for helper functions description, e.g.: * u32 bpf_get_smp_processor_id(void) * ... * Return * ... * Attributes * __bpf_fastcall * Generated header for the example above: #ifndef __bpf_fastcall #if __has_attribute(__bpf_fastcall) #define __bpf_fastcall __attribute__((bpf_fastcall)) #else #define __bpf_fastcall #endif #endif ... __bpf_fastcall static __u32 (* const bpf_get_smp_processor_id)(void) = (void *) 8; The following rules apply: - when present, section must follow 'Return' section; - attribute names are specified on the line following 'Attribute' keyword; - attribute names are separated by spaces; - section ends with an "empty" line (" *\n"). Valid attribute names are recorded in the ATTRS map. ATTRS maps shortcut attribute name to correct C syntax. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20240916091712.2929279-2-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
d1334e88e1
commit
48b13cab1e
@ -37,10 +37,11 @@ class APIElement(object):
|
|||||||
@desc: textual description of the symbol
|
@desc: textual description of the symbol
|
||||||
@ret: (optional) description of any associated return value
|
@ret: (optional) description of any associated return value
|
||||||
"""
|
"""
|
||||||
def __init__(self, proto='', desc='', ret=''):
|
def __init__(self, proto='', desc='', ret='', attrs=[]):
|
||||||
self.proto = proto
|
self.proto = proto
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
self.ret = ret
|
self.ret = ret
|
||||||
|
self.attrs = attrs
|
||||||
|
|
||||||
|
|
||||||
class Helper(APIElement):
|
class Helper(APIElement):
|
||||||
@ -81,6 +82,11 @@ class Helper(APIElement):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
ATTRS = {
|
||||||
|
'__bpf_fastcall': 'bpf_fastcall'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class HeaderParser(object):
|
class HeaderParser(object):
|
||||||
"""
|
"""
|
||||||
An object used to parse a file in order to extract the documentation of a
|
An object used to parse a file in order to extract the documentation of a
|
||||||
@ -111,7 +117,8 @@ class HeaderParser(object):
|
|||||||
proto = self.parse_proto()
|
proto = self.parse_proto()
|
||||||
desc = self.parse_desc(proto)
|
desc = self.parse_desc(proto)
|
||||||
ret = self.parse_ret(proto)
|
ret = self.parse_ret(proto)
|
||||||
return Helper(proto=proto, desc=desc, ret=ret)
|
attrs = self.parse_attrs(proto)
|
||||||
|
return Helper(proto=proto, desc=desc, ret=ret, attrs=attrs)
|
||||||
|
|
||||||
def parse_symbol(self):
|
def parse_symbol(self):
|
||||||
p = re.compile(r' \* ?(BPF\w+)$')
|
p = re.compile(r' \* ?(BPF\w+)$')
|
||||||
@ -192,6 +199,28 @@ class HeaderParser(object):
|
|||||||
raise Exception("No return found for " + proto)
|
raise Exception("No return found for " + proto)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def parse_attrs(self, proto):
|
||||||
|
p = re.compile(r' \* ?(?:\t| {5,8})Attributes$')
|
||||||
|
capture = p.match(self.line)
|
||||||
|
if not capture:
|
||||||
|
return []
|
||||||
|
# Expect a single line with mnemonics for attributes separated by spaces
|
||||||
|
self.line = self.reader.readline()
|
||||||
|
p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
|
||||||
|
capture = p.match(self.line)
|
||||||
|
if not capture:
|
||||||
|
raise Exception("Incomplete 'Attributes' section for " + proto)
|
||||||
|
attrs = capture.group(1).split(' ')
|
||||||
|
for attr in attrs:
|
||||||
|
if attr not in ATTRS:
|
||||||
|
raise Exception("Unexpected attribute '" + attr + "' specified for " + proto)
|
||||||
|
self.line = self.reader.readline()
|
||||||
|
if self.line != ' *\n':
|
||||||
|
raise Exception("Expecting empty line after 'Attributes' section for " + proto)
|
||||||
|
# Prepare a line for next self.parse_* to consume
|
||||||
|
self.line = self.reader.readline()
|
||||||
|
return attrs
|
||||||
|
|
||||||
def seek_to(self, target, help_message, discard_lines = 1):
|
def seek_to(self, target, help_message, discard_lines = 1):
|
||||||
self.reader.seek(0)
|
self.reader.seek(0)
|
||||||
offset = self.reader.read().find(target)
|
offset = self.reader.read().find(target)
|
||||||
@ -789,6 +818,21 @@ class PrinterHelpers(Printer):
|
|||||||
print('%s;' % fwd)
|
print('%s;' % fwd)
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
used_attrs = set()
|
||||||
|
for helper in self.elements:
|
||||||
|
for attr in helper.attrs:
|
||||||
|
used_attrs.add(attr)
|
||||||
|
for attr in sorted(used_attrs):
|
||||||
|
print('#ifndef %s' % attr)
|
||||||
|
print('#if __has_attribute(%s)' % ATTRS[attr])
|
||||||
|
print('#define %s __attribute__((%s))' % (attr, ATTRS[attr]))
|
||||||
|
print('#else')
|
||||||
|
print('#define %s' % attr)
|
||||||
|
print('#endif')
|
||||||
|
print('#endif')
|
||||||
|
if used_attrs:
|
||||||
|
print('')
|
||||||
|
|
||||||
def print_footer(self):
|
def print_footer(self):
|
||||||
footer = ''
|
footer = ''
|
||||||
print(footer)
|
print(footer)
|
||||||
@ -827,7 +871,10 @@ class PrinterHelpers(Printer):
|
|||||||
print(' *{}{}'.format(' \t' if line else '', line))
|
print(' *{}{}'.format(' \t' if line else '', line))
|
||||||
|
|
||||||
print(' */')
|
print(' */')
|
||||||
print('static %s %s(* const %s)(' % (self.map_type(proto['ret_type']),
|
print('static ', end='')
|
||||||
|
if helper.attrs:
|
||||||
|
print('%s ' % (" ".join(helper.attrs)), end='')
|
||||||
|
print('%s %s(* const %s)(' % (self.map_type(proto['ret_type']),
|
||||||
proto['ret_star'], proto['name']), end='')
|
proto['ret_star'], proto['name']), end='')
|
||||||
comma = ''
|
comma = ''
|
||||||
for i, a in enumerate(proto['args']):
|
for i, a in enumerate(proto['args']):
|
||||||
|
Loading…
Reference in New Issue
Block a user