Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/docs/get_abi.py
38179 views
1
#!/usr/bin/env python3
2
# pylint: disable=R0903
3
# Copyright(c) 2025: Mauro Carvalho Chehab <[email protected]>.
4
# SPDX-License-Identifier: GPL-2.0
5
6
"""
7
Parse ABI documentation and produce results from it.
8
"""
9
10
import argparse
11
import logging
12
import os
13
import sys
14
15
# Import Python modules
16
17
LIB_DIR = "../lib/python"
18
SRC_DIR = os.path.dirname(os.path.realpath(__file__))
19
20
sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
21
22
from abi.abi_parser import AbiParser # pylint: disable=C0413
23
from abi.abi_regex import AbiRegex # pylint: disable=C0413
24
from abi.helpers import ABI_DIR, DEBUG_HELP # pylint: disable=C0413
25
from abi.system_symbols import SystemSymbols # pylint: disable=C0413
26
27
# Command line classes
28
29
30
REST_DESC = """
31
Produce output in ReST format.
32
33
The output is done on two sections:
34
35
- Symbols: show all parsed symbols in alphabetic order;
36
- Files: cross reference the content of each file with the symbols on it.
37
"""
38
39
class AbiRest:
40
"""Initialize an argparse subparser for rest output"""
41
42
def __init__(self, subparsers):
43
"""Initialize argparse subparsers"""
44
45
parser = subparsers.add_parser("rest",
46
formatter_class=argparse.RawTextHelpFormatter,
47
description=REST_DESC)
48
49
parser.add_argument("--enable-lineno", action="store_true",
50
help="enable lineno")
51
parser.add_argument("--raw", action="store_true",
52
help="output text as contained in the ABI files. "
53
"It not used, output will contain dynamically"
54
" generated cross references when possible.")
55
parser.add_argument("--no-file", action="store_true",
56
help="Don't the files section")
57
parser.add_argument("--show-hints", help="Show-hints")
58
59
parser.set_defaults(func=self.run)
60
61
def run(self, args):
62
"""Run subparser"""
63
64
parser = AbiParser(args.dir, debug=args.debug)
65
parser.parse_abi()
66
parser.check_issues()
67
68
for t in parser.doc(args.raw, not args.no_file):
69
if args.enable_lineno:
70
print (f".. LINENO {t[1]}#{t[2]}\n\n")
71
72
print(t[0])
73
74
class AbiValidate:
75
"""Initialize an argparse subparser for ABI validation"""
76
77
def __init__(self, subparsers):
78
"""Initialize argparse subparsers"""
79
80
parser = subparsers.add_parser("validate",
81
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
82
description="list events")
83
84
parser.set_defaults(func=self.run)
85
86
def run(self, args):
87
"""Run subparser"""
88
89
parser = AbiParser(args.dir, debug=args.debug)
90
parser.parse_abi()
91
parser.check_issues()
92
93
94
class AbiSearch:
95
"""Initialize an argparse subparser for ABI search"""
96
97
def __init__(self, subparsers):
98
"""Initialize argparse subparsers"""
99
100
parser = subparsers.add_parser("search",
101
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
102
description="Search ABI using a regular expression")
103
104
parser.add_argument("expression",
105
help="Case-insensitive search pattern for the ABI symbol")
106
107
parser.set_defaults(func=self.run)
108
109
def run(self, args):
110
"""Run subparser"""
111
112
parser = AbiParser(args.dir, debug=args.debug)
113
parser.parse_abi()
114
parser.search_symbols(args.expression)
115
116
UNDEFINED_DESC="""
117
Check undefined ABIs on local machine.
118
119
Read sysfs devnodes and check if the devnodes there are defined inside
120
ABI documentation.
121
122
The search logic tries to minimize the number of regular expressions to
123
search per each symbol.
124
125
By default, it runs on a single CPU, as Python support for CPU threads
126
is still experimental, and multi-process runs on Python is very slow.
127
128
On experimental tests, if the number of ABI symbols to search per devnode
129
is contained on a limit of ~150 regular expressions, using a single CPU
130
is a lot faster than using multiple processes. However, if the number of
131
regular expressions to check is at the order of ~30000, using multiple
132
CPUs speeds up the check.
133
"""
134
135
class AbiUndefined:
136
"""
137
Initialize an argparse subparser for logic to check undefined ABI at
138
the current machine's sysfs
139
"""
140
141
def __init__(self, subparsers):
142
"""Initialize argparse subparsers"""
143
144
parser = subparsers.add_parser("undefined",
145
formatter_class=argparse.RawTextHelpFormatter,
146
description=UNDEFINED_DESC)
147
148
parser.add_argument("-S", "--sysfs-dir", default="/sys",
149
help="directory where sysfs is mounted")
150
parser.add_argument("-s", "--search-string",
151
help="search string regular expression to limit symbol search")
152
parser.add_argument("-H", "--show-hints", action="store_true",
153
help="Hints about definitions for missing ABI symbols.")
154
parser.add_argument("-j", "--jobs", "--max-workers", type=int, default=1,
155
help="If bigger than one, enables multiprocessing.")
156
parser.add_argument("-c", "--max-chunk-size", type=int, default=50,
157
help="Maximum number of chunk size")
158
parser.add_argument("-f", "--found", action="store_true",
159
help="Also show found items. "
160
"Helpful to debug the parser."),
161
parser.add_argument("-d", "--dry-run", action="store_true",
162
help="Don't actually search for undefined. "
163
"Helpful to debug the parser."),
164
165
parser.set_defaults(func=self.run)
166
167
def run(self, args):
168
"""Run subparser"""
169
170
abi = AbiRegex(args.dir, debug=args.debug,
171
search_string=args.search_string)
172
173
abi_symbols = SystemSymbols(abi=abi, hints=args.show_hints,
174
sysfs=args.sysfs_dir)
175
176
abi_symbols.check_undefined_symbols(dry_run=args.dry_run,
177
found=args.found,
178
max_workers=args.jobs,
179
chunk_size=args.max_chunk_size)
180
181
182
def main():
183
"""Main program"""
184
185
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
186
187
parser.add_argument("-d", "--debug", type=int, default=0, help="debug level")
188
parser.add_argument("-D", "--dir", default=ABI_DIR, help=DEBUG_HELP)
189
190
subparsers = parser.add_subparsers()
191
192
AbiRest(subparsers)
193
AbiValidate(subparsers)
194
AbiSearch(subparsers)
195
AbiUndefined(subparsers)
196
197
args = parser.parse_args()
198
199
if args.debug:
200
level = logging.DEBUG
201
else:
202
level = logging.INFO
203
204
logging.basicConfig(level=level, format="[%(levelname)s] %(message)s")
205
206
if "func" in args:
207
args.func(args)
208
else:
209
sys.exit(f"Please specify a valid command for {sys.argv[0]}")
210
211
212
# Call main method
213
if __name__ == "__main__":
214
main()
215
216