xref: /linux-6.15/scripts/bpf_doc.py (revision f1f3f67f)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0-only
3#
4# Copyright (C) 2018-2019 Netronome Systems, Inc.
5# Copyright (C) 2021 Isovalent, Inc.
6
7# In case user attempts to run with Python 2.
8from __future__ import print_function
9
10import argparse
11import re
12import sys, os
13
14class NoHelperFound(BaseException):
15    pass
16
17class NoSyscallCommandFound(BaseException):
18    pass
19
20class ParsingError(BaseException):
21    def __init__(self, line='<line not provided>', reader=None):
22        if reader:
23            BaseException.__init__(self,
24                                   'Error at file offset %d, parsing line: %s' %
25                                   (reader.tell(), line))
26        else:
27            BaseException.__init__(self, 'Error parsing line: %s' % line)
28
29
30class APIElement(object):
31    """
32    An object representing the description of an aspect of the eBPF API.
33    @proto: prototype of the API symbol
34    @desc: textual description of the symbol
35    @ret: (optional) description of any associated return value
36    """
37    def __init__(self, proto='', desc='', ret=''):
38        self.proto = proto
39        self.desc = desc
40        self.ret = ret
41
42
43class Helper(APIElement):
44    """
45    An object representing the description of an eBPF helper function.
46    @proto: function prototype of the helper function
47    @desc: textual description of the helper function
48    @ret: description of the return value of the helper function
49    """
50    def proto_break_down(self):
51        """
52        Break down helper function protocol into smaller chunks: return type,
53        name, distincts arguments.
54        """
55        arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$')
56        res = {}
57        proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
58
59        capture = proto_re.match(self.proto)
60        res['ret_type'] = capture.group(1)
61        res['ret_star'] = capture.group(2)
62        res['name']     = capture.group(3)
63        res['args'] = []
64
65        args    = capture.group(4).split(', ')
66        for a in args:
67            capture = arg_re.match(a)
68            res['args'].append({
69                'type' : capture.group(1),
70                'star' : capture.group(5),
71                'name' : capture.group(6)
72            })
73
74        return res
75
76
77class HeaderParser(object):
78    """
79    An object used to parse a file in order to extract the documentation of a
80    list of eBPF helper functions. All the helpers that can be retrieved are
81    stored as Helper object, in the self.helpers() array.
82    @filename: name of file to parse, usually include/uapi/linux/bpf.h in the
83               kernel tree
84    """
85    def __init__(self, filename):
86        self.reader = open(filename, 'r')
87        self.line = ''
88        self.helpers = []
89        self.commands = []
90        self.desc_unique_helpers = set()
91        self.define_unique_helpers = []
92
93    def parse_element(self):
94        proto    = self.parse_symbol()
95        desc     = self.parse_desc(proto)
96        ret      = self.parse_ret(proto)
97        return APIElement(proto=proto, desc=desc, ret=ret)
98
99    def parse_helper(self):
100        proto    = self.parse_proto()
101        desc     = self.parse_desc(proto)
102        ret      = self.parse_ret(proto)
103        return Helper(proto=proto, desc=desc, ret=ret)
104
105    def parse_symbol(self):
106        p = re.compile(' \* ?(.+)$')
107        capture = p.match(self.line)
108        if not capture:
109            raise NoSyscallCommandFound
110        end_re = re.compile(' \* ?NOTES$')
111        end = end_re.match(self.line)
112        if end:
113            raise NoSyscallCommandFound
114        self.line = self.reader.readline()
115        return capture.group(1)
116
117    def parse_proto(self):
118        # Argument can be of shape:
119        #   - "void"
120        #   - "type  name"
121        #   - "type *name"
122        #   - Same as above, with "const" and/or "struct" in front of type
123        #   - "..." (undefined number of arguments, for bpf_trace_printk())
124        # There is at least one term ("void"), and at most five arguments.
125        p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
126        capture = p.match(self.line)
127        if not capture:
128            raise NoHelperFound
129        self.line = self.reader.readline()
130        return capture.group(1)
131
132    def parse_desc(self, proto):
133        p = re.compile(' \* ?(?:\t| {5,8})Description$')
134        capture = p.match(self.line)
135        if not capture:
136            raise Exception("No description section found for " + proto)
137        # Description can be several lines, some of them possibly empty, and it
138        # stops when another subsection title is met.
139        desc = ''
140        desc_present = False
141        while True:
142            self.line = self.reader.readline()
143            if self.line == ' *\n':
144                desc += '\n'
145            else:
146                p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
147                capture = p.match(self.line)
148                if capture:
149                    desc_present = True
150                    desc += capture.group(1) + '\n'
151                else:
152                    break
153
154        if not desc_present:
155            raise Exception("No description found for " + proto)
156        return desc
157
158    def parse_ret(self, proto):
159        p = re.compile(' \* ?(?:\t| {5,8})Return$')
160        capture = p.match(self.line)
161        if not capture:
162            raise Exception("No return section found for " + proto)
163        # Return value description can be several lines, some of them possibly
164        # empty, and it stops when another subsection title is met.
165        ret = ''
166        ret_present = False
167        while True:
168            self.line = self.reader.readline()
169            if self.line == ' *\n':
170                ret += '\n'
171            else:
172                p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
173                capture = p.match(self.line)
174                if capture:
175                    ret_present = True
176                    ret += capture.group(1) + '\n'
177                else:
178                    break
179
180        if not ret_present:
181            raise Exception("No return found for " + proto)
182        return ret
183
184    def seek_to(self, target, help_message):
185        self.reader.seek(0)
186        offset = self.reader.read().find(target)
187        if offset == -1:
188            raise Exception(help_message)
189        self.reader.seek(offset)
190        self.reader.readline()
191        self.reader.readline()
192        self.line = self.reader.readline()
193
194    def parse_syscall(self):
195        self.seek_to('* DOC: eBPF Syscall Commands',
196                     'Could not find start of eBPF syscall descriptions list')
197        while True:
198            try:
199                command = self.parse_element()
200                self.commands.append(command)
201            except NoSyscallCommandFound:
202                break
203
204    def parse_desc_helpers(self):
205        self.seek_to('* Start of BPF helper function descriptions:',
206                     'Could not find start of eBPF helper descriptions list')
207        while True:
208            try:
209                helper = self.parse_helper()
210                self.helpers.append(helper)
211                proto = helper.proto_break_down()
212                self.desc_unique_helpers.add(proto['name'])
213            except NoHelperFound:
214                break
215
216    def parse_define_helpers(self):
217        # Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare
218        # later with the number of unique function names present in description.
219        # Note: seek_to(..) discards the first line below the target search text,
220        # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.
221        self.seek_to('#define __BPF_FUNC_MAPPER(FN)',
222                     'Could not find start of eBPF helper definition list')
223        # Searches for either one or more FN(\w+) defines or a backslash for newline
224        p = re.compile('\s*(FN\(\w+\))+|\\\\')
225        fn_defines_str = ''
226        while True:
227            capture = p.match(self.line)
228            if capture:
229                fn_defines_str += self.line
230            else:
231                break
232            self.line = self.reader.readline()
233        # Find the number of occurences of FN(\w+)
234        self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)
235
236    def run(self):
237        self.parse_syscall()
238        self.parse_desc_helpers()
239        self.parse_define_helpers()
240        self.reader.close()
241
242###############################################################################
243
244class Printer(object):
245    """
246    A generic class for printers. Printers should be created with an array of
247    Helper objects, and implement a way to print them in the desired fashion.
248    @parser: A HeaderParser with objects to print to standard output
249    """
250    def __init__(self, parser):
251        self.parser = parser
252        self.elements = []
253
254    def print_header(self):
255        pass
256
257    def print_footer(self):
258        pass
259
260    def print_one(self, helper):
261        pass
262
263    def print_all(self):
264        self.print_header()
265        for elem in self.elements:
266            self.print_one(elem)
267        self.print_footer()
268
269
270class PrinterRST(Printer):
271    """
272    A generic class for printers that print ReStructured Text. Printers should
273    be created with a HeaderParser object, and implement a way to print API
274    elements in the desired fashion.
275    @parser: A HeaderParser with objects to print to standard output
276    """
277    def __init__(self, parser):
278        self.parser = parser
279
280    def print_license(self):
281        license = '''\
282.. Copyright (C) All BPF authors and contributors from 2014 to present.
283.. See git log include/uapi/linux/bpf.h in kernel tree for details.
284..
285.. %%%LICENSE_START(VERBATIM)
286.. Permission is granted to make and distribute verbatim copies of this
287.. manual provided the copyright notice and this permission notice are
288.. preserved on all copies.
289..
290.. Permission is granted to copy and distribute modified versions of this
291.. manual under the conditions for verbatim copying, provided that the
292.. entire resulting derived work is distributed under the terms of a
293.. permission notice identical to this one.
294..
295.. Since the Linux kernel and libraries are constantly changing, this
296.. manual page may be incorrect or out-of-date.  The author(s) assume no
297.. responsibility for errors or omissions, or for damages resulting from
298.. the use of the information contained herein.  The author(s) may not
299.. have taken the same level of care in the production of this manual,
300.. which is licensed free of charge, as they might when working
301.. professionally.
302..
303.. Formatted or processed versions of this manual, if unaccompanied by
304.. the source, must acknowledge the copyright and authors of this work.
305.. %%%LICENSE_END
306..
307.. Please do not edit this file. It was generated from the documentation
308.. located in file include/uapi/linux/bpf.h of the Linux kernel sources
309.. (helpers description), and from scripts/bpf_doc.py in the same
310.. repository (header and footer).
311'''
312        print(license)
313
314    def print_elem(self, elem):
315        if (elem.desc):
316            print('\tDescription')
317            # Do not strip all newline characters: formatted code at the end of
318            # a section must be followed by a blank line.
319            for line in re.sub('\n$', '', elem.desc, count=1).split('\n'):
320                print('{}{}'.format('\t\t' if line else '', line))
321
322        if (elem.ret):
323            print('\tReturn')
324            for line in elem.ret.rstrip().split('\n'):
325                print('{}{}'.format('\t\t' if line else '', line))
326
327        print('')
328
329def helper_number_check(desc_unique_helpers, define_unique_helpers):
330    """
331    Checks the number of functions documented within the header file
332    with those present as part of #define __BPF_FUNC_MAPPER and raise an
333    Exception if they don't match.
334    """
335    nr_desc_unique_helpers = len(desc_unique_helpers)
336    nr_define_unique_helpers = len(define_unique_helpers)
337    if nr_desc_unique_helpers != nr_define_unique_helpers:
338        helper_exception = '''
339The number of unique helpers in description (%d) doesn\'t match the number of unique helpers defined in __BPF_FUNC_MAPPER (%d)
340''' % (nr_desc_unique_helpers, nr_define_unique_helpers)
341        if nr_desc_unique_helpers < nr_define_unique_helpers:
342            # Function description is parsed until no helper is found (which can be due to
343            # misformatting). Hence, only print the first missing/misformatted function.
344            helper_exception += '''
345The description for %s is not present or formatted correctly.
346''' % (define_unique_helpers[nr_desc_unique_helpers])
347        raise Exception(helper_exception)
348
349class PrinterHelpersRST(PrinterRST):
350    """
351    A printer for dumping collected information about helpers as a ReStructured
352    Text page compatible with the rst2man program, which can be used to
353    generate a manual page for the helpers.
354    @parser: A HeaderParser with Helper objects to print to standard output
355    """
356    def __init__(self, parser):
357        self.elements = parser.helpers
358        helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
359
360    def print_header(self):
361        header = '''\
362===========
363BPF-HELPERS
364===========
365-------------------------------------------------------------------------------
366list of eBPF helper functions
367-------------------------------------------------------------------------------
368
369:Manual section: 7
370
371DESCRIPTION
372===========
373
374The extended Berkeley Packet Filter (eBPF) subsystem consists in programs
375written in a pseudo-assembly language, then attached to one of the several
376kernel hooks and run in reaction of specific events. This framework differs
377from the older, "classic" BPF (or "cBPF") in several aspects, one of them being
378the ability to call special functions (or "helpers") from within a program.
379These functions are restricted to a white-list of helpers defined in the
380kernel.
381
382These helpers are used by eBPF programs to interact with the system, or with
383the context in which they work. For instance, they can be used to print
384debugging messages, to get the time since the system was booted, to interact
385with eBPF maps, or to manipulate network packets. Since there are several eBPF
386program types, and that they do not run in the same context, each program type
387can only call a subset of those helpers.
388
389Due to eBPF conventions, a helper can not have more than five arguments.
390
391Internally, eBPF programs call directly into the compiled helper functions
392without requiring any foreign-function interface. As a result, calling helpers
393introduces no overhead, thus offering excellent performance.
394
395This document is an attempt to list and document the helpers available to eBPF
396developers. They are sorted by chronological order (the oldest helpers in the
397kernel at the top).
398
399HELPERS
400=======
401'''
402        PrinterRST.print_license(self)
403        print(header)
404
405    def print_footer(self):
406        footer = '''
407EXAMPLES
408========
409
410Example usage for most of the eBPF helpers listed in this manual page are
411available within the Linux kernel sources, at the following locations:
412
413* *samples/bpf/*
414* *tools/testing/selftests/bpf/*
415
416LICENSE
417=======
418
419eBPF programs can have an associated license, passed along with the bytecode
420instructions to the kernel when the programs are loaded. The format for that
421string is identical to the one in use for kernel modules (Dual licenses, such
422as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
423programs that are compatible with the GNU Privacy License (GPL).
424
425In order to use such helpers, the eBPF program must be loaded with the correct
426license string passed (via **attr**) to the **bpf**\ () system call, and this
427generally translates into the C source code of the program containing a line
428similar to the following:
429
430::
431
432	char ____license[] __attribute__((section("license"), used)) = "GPL";
433
434IMPLEMENTATION
435==============
436
437This manual page is an effort to document the existing eBPF helper functions.
438But as of this writing, the BPF sub-system is under heavy development. New eBPF
439program or map types are added, along with new helper functions. Some helpers
440are occasionally made available for additional program types. So in spite of
441the efforts of the community, this page might not be up-to-date. If you want to
442check by yourself what helper functions exist in your kernel, or what types of
443programs they can support, here are some files among the kernel tree that you
444may be interested in:
445
446* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list
447  of all helper functions, as well as many other BPF definitions including most
448  of the flags, structs or constants used by the helpers.
449* *net/core/filter.c* contains the definition of most network-related helper
450  functions, and the list of program types from which they can be used.
451* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related
452  helpers.
453* *kernel/bpf/verifier.c* contains the functions used to check that valid types
454  of eBPF maps are used with a given helper function.
455* *kernel/bpf/* directory contains other files in which additional helpers are
456  defined (for cgroups, sockmaps, etc.).
457* The bpftool utility can be used to probe the availability of helper functions
458  on the system (as well as supported program and map types, and a number of
459  other parameters). To do so, run **bpftool feature probe** (see
460  **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to
461  list features available to unprivileged users.
462
463Compatibility between helper functions and program types can generally be found
464in the files where helper functions are defined. Look for the **struct
465bpf_func_proto** objects and for functions returning them: these functions
466contain a list of helpers that a given program type can call. Note that the
467**default:** label of the **switch ... case** used to filter helpers can call
468other functions, themselves allowing access to additional helpers. The
469requirement for GPL license is also in those **struct bpf_func_proto**.
470
471Compatibility between helper functions and map types can be found in the
472**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*.
473
474Helper functions that invalidate the checks on **data** and **data_end**
475pointers for network processing are listed in function
476**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*.
477
478SEE ALSO
479========
480
481**bpf**\ (2),
482**bpftool**\ (8),
483**cgroups**\ (7),
484**ip**\ (8),
485**perf_event_open**\ (2),
486**sendmsg**\ (2),
487**socket**\ (7),
488**tc-bpf**\ (8)'''
489        print(footer)
490
491    def print_proto(self, helper):
492        """
493        Format function protocol with bold and italics markers. This makes RST
494        file less readable, but gives nice results in the manual page.
495        """
496        proto = helper.proto_break_down()
497
498        print('**%s %s%s(' % (proto['ret_type'],
499                              proto['ret_star'].replace('*', '\\*'),
500                              proto['name']),
501              end='')
502
503        comma = ''
504        for a in proto['args']:
505            one_arg = '{}{}'.format(comma, a['type'])
506            if a['name']:
507                if a['star']:
508                    one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*'))
509                else:
510                    one_arg += '** '
511                one_arg += '*{}*\\ **'.format(a['name'])
512            comma = ', '
513            print(one_arg, end='')
514
515        print(')**')
516
517    def print_one(self, helper):
518        self.print_proto(helper)
519        self.print_elem(helper)
520
521
522class PrinterSyscallRST(PrinterRST):
523    """
524    A printer for dumping collected information about the syscall API as a
525    ReStructured Text page compatible with the rst2man program, which can be
526    used to generate a manual page for the syscall.
527    @parser: A HeaderParser with APIElement objects to print to standard
528             output
529    """
530    def __init__(self, parser):
531        self.elements = parser.commands
532
533    def print_header(self):
534        header = '''\
535===
536bpf
537===
538-------------------------------------------------------------------------------
539Perform a command on an extended BPF object
540-------------------------------------------------------------------------------
541
542:Manual section: 2
543
544COMMANDS
545========
546'''
547        PrinterRST.print_license(self)
548        print(header)
549
550    def print_one(self, command):
551        print('**%s**' % (command.proto))
552        self.print_elem(command)
553
554
555class PrinterHelpers(Printer):
556    """
557    A printer for dumping collected information about helpers as C header to
558    be included from BPF program.
559    @parser: A HeaderParser with Helper objects to print to standard output
560    """
561    def __init__(self, parser):
562        self.elements = parser.helpers
563        helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
564
565    type_fwds = [
566            'struct bpf_fib_lookup',
567            'struct bpf_sk_lookup',
568            'struct bpf_perf_event_data',
569            'struct bpf_perf_event_value',
570            'struct bpf_pidns_info',
571            'struct bpf_redir_neigh',
572            'struct bpf_sock',
573            'struct bpf_sock_addr',
574            'struct bpf_sock_ops',
575            'struct bpf_sock_tuple',
576            'struct bpf_spin_lock',
577            'struct bpf_sysctl',
578            'struct bpf_tcp_sock',
579            'struct bpf_tunnel_key',
580            'struct bpf_xfrm_state',
581            'struct linux_binprm',
582            'struct pt_regs',
583            'struct sk_reuseport_md',
584            'struct sockaddr',
585            'struct tcphdr',
586            'struct seq_file',
587            'struct tcp6_sock',
588            'struct tcp_sock',
589            'struct tcp_timewait_sock',
590            'struct tcp_request_sock',
591            'struct udp6_sock',
592            'struct unix_sock',
593            'struct task_struct',
594
595            'struct __sk_buff',
596            'struct sk_msg_md',
597            'struct xdp_md',
598            'struct path',
599            'struct btf_ptr',
600            'struct inode',
601            'struct socket',
602            'struct file',
603            'struct bpf_timer',
604    ]
605    known_types = {
606            '...',
607            'void',
608            'const void',
609            'char',
610            'const char',
611            'int',
612            'long',
613            'unsigned long',
614
615            '__be16',
616            '__be32',
617            '__wsum',
618
619            'struct bpf_fib_lookup',
620            'struct bpf_perf_event_data',
621            'struct bpf_perf_event_value',
622            'struct bpf_pidns_info',
623            'struct bpf_redir_neigh',
624            'struct bpf_sk_lookup',
625            'struct bpf_sock',
626            'struct bpf_sock_addr',
627            'struct bpf_sock_ops',
628            'struct bpf_sock_tuple',
629            'struct bpf_spin_lock',
630            'struct bpf_sysctl',
631            'struct bpf_tcp_sock',
632            'struct bpf_tunnel_key',
633            'struct bpf_xfrm_state',
634            'struct linux_binprm',
635            'struct pt_regs',
636            'struct sk_reuseport_md',
637            'struct sockaddr',
638            'struct tcphdr',
639            'struct seq_file',
640            'struct tcp6_sock',
641            'struct tcp_sock',
642            'struct tcp_timewait_sock',
643            'struct tcp_request_sock',
644            'struct udp6_sock',
645            'struct unix_sock',
646            'struct task_struct',
647            'struct path',
648            'struct btf_ptr',
649            'struct inode',
650            'struct socket',
651            'struct file',
652            'struct bpf_timer',
653    }
654    mapped_types = {
655            'u8': '__u8',
656            'u16': '__u16',
657            'u32': '__u32',
658            'u64': '__u64',
659            's8': '__s8',
660            's16': '__s16',
661            's32': '__s32',
662            's64': '__s64',
663            'size_t': 'unsigned long',
664            'struct bpf_map': 'void',
665            'struct sk_buff': 'struct __sk_buff',
666            'const struct sk_buff': 'const struct __sk_buff',
667            'struct sk_msg_buff': 'struct sk_msg_md',
668            'struct xdp_buff': 'struct xdp_md',
669    }
670    # Helpers overloaded for different context types.
671    overloaded_helpers = [
672        'bpf_get_socket_cookie',
673        'bpf_sk_assign',
674    ]
675
676    def print_header(self):
677        header = '''\
678/* This is auto-generated file. See bpf_doc.py for details. */
679
680/* Forward declarations of BPF structs */'''
681
682        print(header)
683        for fwd in self.type_fwds:
684            print('%s;' % fwd)
685        print('')
686
687    def print_footer(self):
688        footer = ''
689        print(footer)
690
691    def map_type(self, t):
692        if t in self.known_types:
693            return t
694        if t in self.mapped_types:
695            return self.mapped_types[t]
696        print("Unrecognized type '%s', please add it to known types!" % t,
697              file=sys.stderr)
698        sys.exit(1)
699
700    seen_helpers = set()
701
702    def print_one(self, helper):
703        proto = helper.proto_break_down()
704
705        if proto['name'] in self.seen_helpers:
706            return
707        self.seen_helpers.add(proto['name'])
708
709        print('/*')
710        print(" * %s" % proto['name'])
711        print(" *")
712        if (helper.desc):
713            # Do not strip all newline characters: formatted code at the end of
714            # a section must be followed by a blank line.
715            for line in re.sub('\n$', '', helper.desc, count=1).split('\n'):
716                print(' *{}{}'.format(' \t' if line else '', line))
717
718        if (helper.ret):
719            print(' *')
720            print(' * Returns')
721            for line in helper.ret.rstrip().split('\n'):
722                print(' *{}{}'.format(' \t' if line else '', line))
723
724        print(' */')
725        print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
726                                      proto['ret_star'], proto['name']), end='')
727        comma = ''
728        for i, a in enumerate(proto['args']):
729            t = a['type']
730            n = a['name']
731            if proto['name'] in self.overloaded_helpers and i == 0:
732                    t = 'void'
733                    n = 'ctx'
734            one_arg = '{}{}'.format(comma, self.map_type(t))
735            if n:
736                if a['star']:
737                    one_arg += ' {}'.format(a['star'])
738                else:
739                    one_arg += ' '
740                one_arg += '{}'.format(n)
741            comma = ', '
742            print(one_arg, end='')
743
744        print(') = (void *) %d;' % len(self.seen_helpers))
745        print('')
746
747###############################################################################
748
749# If script is launched from scripts/ from kernel tree and can access
750# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse,
751# otherwise the --filename argument will be required from the command line.
752script = os.path.abspath(sys.argv[0])
753linuxRoot = os.path.dirname(os.path.dirname(script))
754bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h')
755
756printers = {
757        'helpers': PrinterHelpersRST,
758        'syscall': PrinterSyscallRST,
759}
760
761argParser = argparse.ArgumentParser(description="""
762Parse eBPF header file and generate documentation for the eBPF API.
763The RST-formatted output produced can be turned into a manual page with the
764rst2man utility.
765""")
766argParser.add_argument('--header', action='store_true',
767                       help='generate C header file')
768if (os.path.isfile(bpfh)):
769    argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
770                           default=bpfh)
771else:
772    argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h')
773argParser.add_argument('target', nargs='?', default='helpers',
774                       choices=printers.keys(), help='eBPF API target')
775args = argParser.parse_args()
776
777# Parse file.
778headerParser = HeaderParser(args.filename)
779headerParser.run()
780
781# Print formatted output to standard output.
782if args.header:
783    if args.target != 'helpers':
784        raise NotImplementedError('Only helpers header generation is supported')
785    printer = PrinterHelpers(headerParser)
786else:
787    printer = printers[args.target](headerParser)
788printer.print_all()
789