8
8
from __future__ import print_function
9
9
10
10
import argparse
11
+ import json
11
12
import re
12
13
import sys , os
13
14
import subprocess
@@ -37,11 +38,17 @@ class APIElement(object):
37
38
@desc: textual description of the symbol
38
39
@ret: (optional) description of any associated return value
39
40
"""
40
- def __init__ (self , proto = '' , desc = '' , ret = '' , attrs = [] ):
41
+ def __init__ (self , proto = '' , desc = '' , ret = '' ):
41
42
self .proto = proto
42
43
self .desc = desc
43
44
self .ret = ret
44
- self .attrs = attrs
45
+
46
+ def to_dict (self ):
47
+ return {
48
+ 'proto' : self .proto ,
49
+ 'desc' : self .desc ,
50
+ 'ret' : self .ret
51
+ }
45
52
46
53
47
54
class Helper (APIElement ):
@@ -51,8 +58,9 @@ class Helper(APIElement):
51
58
@desc: textual description of the helper function
52
59
@ret: description of the return value of the helper function
53
60
"""
54
- def __init__ (self , * args , ** kwargs ):
55
- super ().__init__ (* args , ** kwargs )
61
+ def __init__ (self , proto = '' , desc = '' , ret = '' , attrs = []):
62
+ super ().__init__ (proto , desc , ret )
63
+ self .attrs = attrs
56
64
self .enum_val = None
57
65
58
66
def proto_break_down (self ):
@@ -81,6 +89,12 @@ def proto_break_down(self):
81
89
82
90
return res
83
91
92
+ def to_dict (self ):
93
+ d = super ().to_dict ()
94
+ d ["attrs" ] = self .attrs
95
+ d .update (self .proto_break_down ())
96
+ return d
97
+
84
98
85
99
ATTRS = {
86
100
'__bpf_fastcall' : 'bpf_fastcall'
@@ -675,7 +689,7 @@ def print_one(self, command):
675
689
self .print_elem (command )
676
690
677
691
678
- class PrinterHelpers (Printer ):
692
+ class PrinterHelpersHeader (Printer ):
679
693
"""
680
694
A printer for dumping collected information about helpers as C header to
681
695
be included from BPF program.
@@ -896,6 +910,43 @@ def print_one(self, helper):
896
910
print (') = (void *) %d;' % helper .enum_val )
897
911
print ('' )
898
912
913
+
914
+ class PrinterHelpersJSON (Printer ):
915
+ """
916
+ A printer for dumping collected information about helpers as a JSON file.
917
+ @parser: A HeaderParser with Helper objects
918
+ """
919
+
920
+ def __init__ (self , parser ):
921
+ self .elements = parser .helpers
922
+ self .elem_number_check (
923
+ parser .desc_unique_helpers ,
924
+ parser .define_unique_helpers ,
925
+ "helper" ,
926
+ "___BPF_FUNC_MAPPER" ,
927
+ )
928
+
929
+ def print_all (self ):
930
+ helper_dicts = [helper .to_dict () for helper in self .elements ]
931
+ out_dict = {'helpers' : helper_dicts }
932
+ print (json .dumps (out_dict , indent = 4 ))
933
+
934
+
935
+ class PrinterSyscallJSON (Printer ):
936
+ """
937
+ A printer for dumping collected syscall information as a JSON file.
938
+ @parser: A HeaderParser with APIElement objects
939
+ """
940
+
941
+ def __init__ (self , parser ):
942
+ self .elements = parser .commands
943
+ self .elem_number_check (parser .desc_syscalls , parser .enum_syscalls , 'syscall' , 'bpf_cmd' )
944
+
945
+ def print_all (self ):
946
+ syscall_dicts = [syscall .to_dict () for syscall in self .elements ]
947
+ out_dict = {'syscall' : syscall_dicts }
948
+ print (json .dumps (out_dict , indent = 4 ))
949
+
899
950
###############################################################################
900
951
901
952
# If script is launched from scripts/ from kernel tree and can access
@@ -905,9 +956,17 @@ def print_one(self, helper):
905
956
linuxRoot = os .path .dirname (os .path .dirname (script ))
906
957
bpfh = os .path .join (linuxRoot , 'include/uapi/linux/bpf.h' )
907
958
959
+ # target -> output format -> printer
908
960
printers = {
909
- 'helpers' : PrinterHelpersRST ,
910
- 'syscall' : PrinterSyscallRST ,
961
+ 'helpers' : {
962
+ 'rst' : PrinterHelpersRST ,
963
+ 'json' : PrinterHelpersJSON ,
964
+ 'header' : PrinterHelpersHeader ,
965
+ },
966
+ 'syscall' : {
967
+ 'rst' : PrinterSyscallRST ,
968
+ 'json' : PrinterSyscallJSON
969
+ },
911
970
}
912
971
913
972
argParser = argparse .ArgumentParser (description = """
@@ -917,24 +976,44 @@ def print_one(self, helper):
917
976
""" )
918
977
argParser .add_argument ('--header' , action = 'store_true' ,
919
978
help = 'generate C header file' )
979
+ argParser .add_argument ('--json' , action = 'store_true' ,
980
+ help = 'generate a JSON' )
920
981
if (os .path .isfile (bpfh )):
921
982
argParser .add_argument ('--filename' , help = 'path to include/uapi/linux/bpf.h' ,
922
983
default = bpfh )
923
984
else :
924
985
argParser .add_argument ('--filename' , help = 'path to include/uapi/linux/bpf.h' )
925
986
argParser .add_argument ('target' , nargs = '?' , default = 'helpers' ,
926
987
choices = printers .keys (), help = 'eBPF API target' )
927
- args = argParser .parse_args ()
928
-
929
- # Parse file.
930
- headerParser = HeaderParser (args .filename )
931
- headerParser .run ()
932
988
933
- # Print formatted output to standard output.
934
- if args .header :
935
- if args .target != 'helpers' :
936
- raise NotImplementedError ('Only helpers header generation is supported' )
937
- printer = PrinterHelpers (headerParser )
938
- else :
939
- printer = printers [args .target ](headerParser )
940
- printer .print_all ()
989
+ def error_die (message : str ):
990
+ argParser .print_usage (file = sys .stderr )
991
+ print ('Error: {}' .format (message ), file = sys .stderr )
992
+ exit (1 )
993
+
994
+ def parse_and_dump ():
995
+ args = argParser .parse_args ()
996
+
997
+ # Parse file.
998
+ headerParser = HeaderParser (args .filename )
999
+ headerParser .run ()
1000
+
1001
+ if args .header and args .json :
1002
+ error_die ('Use either --header or --json, not both' )
1003
+
1004
+ output_format = 'rst'
1005
+ if args .header :
1006
+ output_format = 'header'
1007
+ elif args .json :
1008
+ output_format = 'json'
1009
+
1010
+ try :
1011
+ printer = printers [args .target ][output_format ](headerParser )
1012
+ # Print formatted output to standard output.
1013
+ printer .print_all ()
1014
+ except KeyError :
1015
+ error_die ('Unsupported target/format combination: "{}", "{}"'
1016
+ .format (args .target , output_format ))
1017
+
1018
+ if __name__ == "__main__" :
1019
+ parse_and_dump ()
0 commit comments