xref: /linux/scripts/get_abi.py (revision 0d5fd96880d9135a4b35fb5523896b21b13dde78)
1484e9aa6SMauro Carvalho Chehab#!/usr/bin/env python3
2484e9aa6SMauro Carvalho Chehab# pylint: disable=R0903
3484e9aa6SMauro Carvalho Chehab# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
4484e9aa6SMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0
5484e9aa6SMauro Carvalho Chehab
6484e9aa6SMauro Carvalho Chehab"""
7484e9aa6SMauro Carvalho ChehabParse ABI documentation and produce results from it.
8484e9aa6SMauro Carvalho Chehab"""
9484e9aa6SMauro Carvalho Chehab
10484e9aa6SMauro Carvalho Chehabimport argparse
11484e9aa6SMauro Carvalho Chehabimport logging
12484e9aa6SMauro Carvalho Chehabimport os
13484e9aa6SMauro Carvalho Chehabimport sys
14484e9aa6SMauro Carvalho Chehab
15484e9aa6SMauro Carvalho Chehab# Import Python modules
16484e9aa6SMauro Carvalho Chehab
17484e9aa6SMauro Carvalho ChehabLIB_DIR = "lib/abi"
18484e9aa6SMauro Carvalho ChehabSRC_DIR = os.path.dirname(os.path.realpath(__file__))
19484e9aa6SMauro Carvalho Chehab
20484e9aa6SMauro Carvalho Chehabsys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
21484e9aa6SMauro Carvalho Chehab
22484e9aa6SMauro Carvalho Chehabfrom abi_parser import AbiParser                # pylint: disable=C0413
23*0d5fd968SMauro Carvalho Chehabfrom abi_regex import AbiRegex                  # pylint: disable=C0413
24484e9aa6SMauro Carvalho Chehabfrom helpers import ABI_DIR, DEBUG_HELP         # pylint: disable=C0413
25*0d5fd968SMauro Carvalho Chehabfrom system_symbols import SystemSymbols        # pylint: disable=C0413
26484e9aa6SMauro Carvalho Chehab
27484e9aa6SMauro Carvalho Chehab# Command line classes
28484e9aa6SMauro Carvalho Chehab
29484e9aa6SMauro Carvalho Chehab
30484e9aa6SMauro Carvalho ChehabREST_DESC = """
31484e9aa6SMauro Carvalho ChehabProduce output in ReST format.
32484e9aa6SMauro Carvalho Chehab
33484e9aa6SMauro Carvalho ChehabThe output is done on two sections:
34484e9aa6SMauro Carvalho Chehab
35484e9aa6SMauro Carvalho Chehab- Symbols: show all parsed symbols in alphabetic order;
36484e9aa6SMauro Carvalho Chehab- Files: cross reference the content of each file with the symbols on it.
37484e9aa6SMauro Carvalho Chehab"""
38484e9aa6SMauro Carvalho Chehab
39484e9aa6SMauro Carvalho Chehabclass AbiRest:
40484e9aa6SMauro Carvalho Chehab    """Initialize an argparse subparser for rest output"""
41484e9aa6SMauro Carvalho Chehab
42484e9aa6SMauro Carvalho Chehab    def __init__(self, subparsers):
43484e9aa6SMauro Carvalho Chehab        """Initialize argparse subparsers"""
44484e9aa6SMauro Carvalho Chehab
45484e9aa6SMauro Carvalho Chehab        parser = subparsers.add_parser("rest",
46484e9aa6SMauro Carvalho Chehab                                       formatter_class=argparse.RawTextHelpFormatter,
47484e9aa6SMauro Carvalho Chehab                                       description=REST_DESC)
48484e9aa6SMauro Carvalho Chehab
49484e9aa6SMauro Carvalho Chehab        parser.add_argument("--enable-lineno",  action="store_true",
50484e9aa6SMauro Carvalho Chehab                            help="enable lineno")
51484e9aa6SMauro Carvalho Chehab        parser.add_argument("--raw", action="store_true",
52484e9aa6SMauro Carvalho Chehab                            help="output text as contained in the ABI files. "
53484e9aa6SMauro Carvalho Chehab                                 "It not used, output will contain dynamically"
54484e9aa6SMauro Carvalho Chehab                                 " generated cross references when possible.")
55484e9aa6SMauro Carvalho Chehab        parser.add_argument("--no-file", action="store_true",
56484e9aa6SMauro Carvalho Chehab                            help="Don't the files section")
57484e9aa6SMauro Carvalho Chehab        parser.add_argument("--show-hints", help="Show-hints")
58484e9aa6SMauro Carvalho Chehab
59484e9aa6SMauro Carvalho Chehab        parser.set_defaults(func=self.run)
60484e9aa6SMauro Carvalho Chehab
61484e9aa6SMauro Carvalho Chehab    def run(self, args):
62484e9aa6SMauro Carvalho Chehab        """Run subparser"""
63484e9aa6SMauro Carvalho Chehab
64484e9aa6SMauro Carvalho Chehab        parser = AbiParser(args.dir, debug=args.debug)
65484e9aa6SMauro Carvalho Chehab        parser.parse_abi()
66484e9aa6SMauro Carvalho Chehab        parser.check_issues()
67484e9aa6SMauro Carvalho Chehab
68aea5e52dSMauro Carvalho Chehab        for t in parser.doc(args.raw, not args.no_file):
69aea5e52dSMauro Carvalho Chehab            if args.enable_lineno:
70aea5e52dSMauro Carvalho Chehab                print (f".. LINENO {t[1]}#{t[2]}\n\n")
71aea5e52dSMauro Carvalho Chehab
72aea5e52dSMauro Carvalho Chehab            print(t[0])
73484e9aa6SMauro Carvalho Chehab
74484e9aa6SMauro Carvalho Chehabclass AbiValidate:
75484e9aa6SMauro Carvalho Chehab    """Initialize an argparse subparser for ABI validation"""
76484e9aa6SMauro Carvalho Chehab
77484e9aa6SMauro Carvalho Chehab    def __init__(self, subparsers):
78484e9aa6SMauro Carvalho Chehab        """Initialize argparse subparsers"""
79484e9aa6SMauro Carvalho Chehab
80484e9aa6SMauro Carvalho Chehab        parser = subparsers.add_parser("validate",
81484e9aa6SMauro Carvalho Chehab                                       formatter_class=argparse.ArgumentDefaultsHelpFormatter,
82484e9aa6SMauro Carvalho Chehab                                       description="list events")
83484e9aa6SMauro Carvalho Chehab
84484e9aa6SMauro Carvalho Chehab        parser.set_defaults(func=self.run)
85484e9aa6SMauro Carvalho Chehab
86484e9aa6SMauro Carvalho Chehab    def run(self, args):
87484e9aa6SMauro Carvalho Chehab        """Run subparser"""
88484e9aa6SMauro Carvalho Chehab
89484e9aa6SMauro Carvalho Chehab        parser = AbiParser(args.dir, debug=args.debug)
90484e9aa6SMauro Carvalho Chehab        parser.parse_abi()
91484e9aa6SMauro Carvalho Chehab        parser.check_issues()
92484e9aa6SMauro Carvalho Chehab
93484e9aa6SMauro Carvalho Chehab
946b48bea1SMauro Carvalho Chehabclass AbiSearch:
956b48bea1SMauro Carvalho Chehab    """Initialize an argparse subparser for ABI search"""
966b48bea1SMauro Carvalho Chehab
976b48bea1SMauro Carvalho Chehab    def __init__(self, subparsers):
986b48bea1SMauro Carvalho Chehab        """Initialize argparse subparsers"""
996b48bea1SMauro Carvalho Chehab
1006b48bea1SMauro Carvalho Chehab        parser = subparsers.add_parser("search",
1016b48bea1SMauro Carvalho Chehab                                       formatter_class=argparse.ArgumentDefaultsHelpFormatter,
1026b48bea1SMauro Carvalho Chehab                                       description="Search ABI using a regular expression")
1036b48bea1SMauro Carvalho Chehab
1046b48bea1SMauro Carvalho Chehab        parser.add_argument("expression",
1056b48bea1SMauro Carvalho Chehab                            help="Case-insensitive search pattern for the ABI symbol")
1066b48bea1SMauro Carvalho Chehab
1076b48bea1SMauro Carvalho Chehab        parser.set_defaults(func=self.run)
1086b48bea1SMauro Carvalho Chehab
1096b48bea1SMauro Carvalho Chehab    def run(self, args):
1106b48bea1SMauro Carvalho Chehab        """Run subparser"""
1116b48bea1SMauro Carvalho Chehab
1126b48bea1SMauro Carvalho Chehab        parser = AbiParser(args.dir, debug=args.debug)
1136b48bea1SMauro Carvalho Chehab        parser.parse_abi()
1146b48bea1SMauro Carvalho Chehab        parser.search_symbols(args.expression)
1156b48bea1SMauro Carvalho Chehab
116*0d5fd968SMauro Carvalho ChehabUNDEFINED_DESC="""
117*0d5fd968SMauro Carvalho ChehabCheck undefined ABIs on local machine.
118*0d5fd968SMauro Carvalho Chehab
119*0d5fd968SMauro Carvalho ChehabRead sysfs devnodes and check if the devnodes there are defined inside
120*0d5fd968SMauro Carvalho ChehabABI documentation.
121*0d5fd968SMauro Carvalho Chehab
122*0d5fd968SMauro Carvalho ChehabThe search logic tries to minimize the number of regular expressions to
123*0d5fd968SMauro Carvalho Chehabsearch per each symbol.
124*0d5fd968SMauro Carvalho Chehab
125*0d5fd968SMauro Carvalho ChehabBy default, it runs on a single CPU, as Python support for CPU threads
126*0d5fd968SMauro Carvalho Chehabis still experimental, and multi-process runs on Python is very slow.
127*0d5fd968SMauro Carvalho Chehab
128*0d5fd968SMauro Carvalho ChehabOn experimental tests, if the number of ABI symbols to search per devnode
129*0d5fd968SMauro Carvalho Chehabis contained on a limit of ~150 regular expressions, using a single CPU
130*0d5fd968SMauro Carvalho Chehabis a lot faster than using multiple processes. However, if the number of
131*0d5fd968SMauro Carvalho Chehabregular expressions to check is at the order of ~30000, using multiple
132*0d5fd968SMauro Carvalho ChehabCPUs speeds up the check.
133*0d5fd968SMauro Carvalho Chehab"""
134*0d5fd968SMauro Carvalho Chehab
135*0d5fd968SMauro Carvalho Chehabclass AbiUndefined:
136*0d5fd968SMauro Carvalho Chehab    """
137*0d5fd968SMauro Carvalho Chehab    Initialize an argparse subparser for logic to check undefined ABI at
138*0d5fd968SMauro Carvalho Chehab    the current machine's sysfs
139*0d5fd968SMauro Carvalho Chehab    """
140*0d5fd968SMauro Carvalho Chehab
141*0d5fd968SMauro Carvalho Chehab    def __init__(self, subparsers):
142*0d5fd968SMauro Carvalho Chehab        """Initialize argparse subparsers"""
143*0d5fd968SMauro Carvalho Chehab
144*0d5fd968SMauro Carvalho Chehab        parser = subparsers.add_parser("undefined",
145*0d5fd968SMauro Carvalho Chehab                                       formatter_class=argparse.RawTextHelpFormatter,
146*0d5fd968SMauro Carvalho Chehab                                       description=UNDEFINED_DESC)
147*0d5fd968SMauro Carvalho Chehab
148*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-S", "--sysfs-dir", default="/sys",
149*0d5fd968SMauro Carvalho Chehab                            help="directory where sysfs is mounted")
150*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-s", "--search-string",
151*0d5fd968SMauro Carvalho Chehab                            help="search string regular expression to limit symbol search")
152*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-H", "--show-hints", action="store_true",
153*0d5fd968SMauro Carvalho Chehab                            help="Hints about definitions for missing ABI symbols.")
154*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-j", "--jobs", "--max-workers", type=int, default=1,
155*0d5fd968SMauro Carvalho Chehab                            help="If bigger than one, enables multiprocessing.")
156*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-c", "--max-chunk-size", type=int, default=50,
157*0d5fd968SMauro Carvalho Chehab                            help="Maximum number of chunk size")
158*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-f", "--found", action="store_true",
159*0d5fd968SMauro Carvalho Chehab                            help="Also show found items. "
160*0d5fd968SMauro Carvalho Chehab                                 "Helpful to debug the parser."),
161*0d5fd968SMauro Carvalho Chehab        parser.add_argument("-d", "--dry-run", action="store_true",
162*0d5fd968SMauro Carvalho Chehab                            help="Don't actually search for undefined. "
163*0d5fd968SMauro Carvalho Chehab                                 "Helpful to debug the parser."),
164*0d5fd968SMauro Carvalho Chehab
165*0d5fd968SMauro Carvalho Chehab        parser.set_defaults(func=self.run)
166*0d5fd968SMauro Carvalho Chehab
167*0d5fd968SMauro Carvalho Chehab    def run(self, args):
168*0d5fd968SMauro Carvalho Chehab        """Run subparser"""
169*0d5fd968SMauro Carvalho Chehab
170*0d5fd968SMauro Carvalho Chehab        abi = AbiRegex(args.dir, debug=args.debug,
171*0d5fd968SMauro Carvalho Chehab                       search_string=args.search_string)
172*0d5fd968SMauro Carvalho Chehab
173*0d5fd968SMauro Carvalho Chehab        abi_symbols = SystemSymbols(abi=abi, hints=args.show_hints,
174*0d5fd968SMauro Carvalho Chehab                                    sysfs=args.sysfs_dir)
175*0d5fd968SMauro Carvalho Chehab
176*0d5fd968SMauro Carvalho Chehab        abi_symbols.check_undefined_symbols(dry_run=args.dry_run,
177*0d5fd968SMauro Carvalho Chehab                                            found=args.found,
178*0d5fd968SMauro Carvalho Chehab                                            max_workers=args.jobs,
179*0d5fd968SMauro Carvalho Chehab                                            chunk_size=args.max_chunk_size)
180*0d5fd968SMauro Carvalho Chehab
1816b48bea1SMauro Carvalho Chehab
182484e9aa6SMauro Carvalho Chehabdef main():
183484e9aa6SMauro Carvalho Chehab    """Main program"""
184484e9aa6SMauro Carvalho Chehab
185484e9aa6SMauro Carvalho Chehab    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
186484e9aa6SMauro Carvalho Chehab
187484e9aa6SMauro Carvalho Chehab    parser.add_argument("-d", "--debug", type=int, default=0, help="debug level")
188484e9aa6SMauro Carvalho Chehab    parser.add_argument("-D", "--dir", default=ABI_DIR, help=DEBUG_HELP)
189484e9aa6SMauro Carvalho Chehab
190484e9aa6SMauro Carvalho Chehab    subparsers = parser.add_subparsers()
191484e9aa6SMauro Carvalho Chehab
192484e9aa6SMauro Carvalho Chehab    AbiRest(subparsers)
193484e9aa6SMauro Carvalho Chehab    AbiValidate(subparsers)
1946b48bea1SMauro Carvalho Chehab    AbiSearch(subparsers)
195*0d5fd968SMauro Carvalho Chehab    AbiUndefined(subparsers)
196484e9aa6SMauro Carvalho Chehab
197484e9aa6SMauro Carvalho Chehab    args = parser.parse_args()
198484e9aa6SMauro Carvalho Chehab
199484e9aa6SMauro Carvalho Chehab    if args.debug:
200484e9aa6SMauro Carvalho Chehab        level = logging.DEBUG
201484e9aa6SMauro Carvalho Chehab    else:
202484e9aa6SMauro Carvalho Chehab        level = logging.INFO
203484e9aa6SMauro Carvalho Chehab
204484e9aa6SMauro Carvalho Chehab    logging.basicConfig(level=level, format="[%(levelname)s] %(message)s")
205484e9aa6SMauro Carvalho Chehab
206484e9aa6SMauro Carvalho Chehab    if "func" in args:
207484e9aa6SMauro Carvalho Chehab        args.func(args)
208484e9aa6SMauro Carvalho Chehab    else:
209484e9aa6SMauro Carvalho Chehab        sys.exit(f"Please specify a valid command for {sys.argv[0]}")
210484e9aa6SMauro Carvalho Chehab
211484e9aa6SMauro Carvalho Chehab
212484e9aa6SMauro Carvalho Chehab# Call main method
213484e9aa6SMauro Carvalho Chehabif __name__ == "__main__":
214484e9aa6SMauro Carvalho Chehab    main()
215