-
Notifications
You must be signed in to change notification settings - Fork 161
/
Copy pathlist_undefined.py
156 lines (123 loc) · 4.9 KB
/
list_undefined.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Prints a list of symbols that are referenced in the Kconfig files of some
# architecture but not defined by the Kconfig files of any architecture.
#
# A Kconfig file might be shared between many architectures and legitimately
# reference undefined symbols for some of them, but if no architecture defines
# the symbol, it usually indicates a problem or potential cleanup.
#
# This script could be sped up a lot if needed. See the comment near the
# referencing_nodes() call.
#
# Run with the following command in the kernel root:
#
# $ python(3) Kconfiglib/examples/list_undefined.py
#
# Example output:
#
# Registering defined and undefined symbols for all arches
# Processing mips
# Processing ia64
# Processing metag
# ...
#
# Finding references to each undefined symbol
# Processing mips
# Processing ia64
# Processing metag
# ...
#
# The following globally undefined symbols were found, listed here
# together with the locations of the items that reference them.
# References might come from enclosing menus and ifs.
#
# ARM_ERRATA_753970: arch/arm/mach-mvebu/Kconfig:56, arch/arm/mach-mvebu/Kconfig:39
# SUNXI_CCU_MP: drivers/clk/sunxi-ng/Kconfig:14
# SUNXI_CCU_DIV: drivers/clk/sunxi-ng/Kconfig:14
# AC97: sound/ac97/Kconfig:6
# ...
import os
import subprocess
from kconfiglib import Kconfig
# Referenced inside the Kconfig files
os.environ["KERNELVERSION"] = str(
subprocess.check_output(("make", "kernelversion")).decode("utf-8").rstrip()
)
def all_arch_srcarch_pairs():
"""
Generates all valid (ARCH, SRCARCH) tuples for the kernel, corresponding to
different architectures. SRCARCH holds the arch/ subdirectory.
"""
for srcarch in os.listdir("arch"):
# Each subdirectory of arch/ containing a Kconfig file corresponds to
# an architecture
if os.path.exists(os.path.join("arch", srcarch, "Kconfig")):
yield (srcarch, srcarch)
# Some architectures define additional ARCH settings with ARCH != SRCARCH
# (search for "Additional ARCH settings for" in the top-level Makefile)
yield ("i386", "x86")
yield ("x86_64", "x86")
yield ("sparc32", "sparc")
yield ("sparc64", "sparc")
yield ("sh64", "sh")
yield ("um", "um")
def all_arch_srcarch_kconfigs():
"""
Generates Kconfig instances for all the architectures in the kernel
"""
os.environ["srctree"] = "."
os.environ["HOSTCC"] = "gcc"
os.environ["HOSTCXX"] = "g++"
os.environ["CC"] = "gcc"
os.environ["LD"] = "ld"
for arch, srcarch in all_arch_srcarch_pairs():
print(" Processing " + arch)
os.environ["ARCH"] = arch
os.environ["SRCARCH"] = srcarch
# um (User Mode Linux) uses a different base Kconfig file
yield Kconfig("Kconfig" if arch != "um" else "arch/x86/um/Kconfig",
warn=False)
print("Registering defined and undefined symbols for all arches")
# Sets holding the names of all defined and undefined symbols, for all
# architectures
defined = set()
undefined = set()
for kconf in all_arch_srcarch_kconfigs():
for name, sym in kconf.syms.items():
if sym.nodes:
# If the symbol has a menu node, it is defined
defined.add(name)
else:
# Undefined symbol. We skip some of the uninteresting ones.
# Due to how Kconfig works, integer literals show up as symbols
# (from e.g. 'default 1'). Skip those.
try:
int(name, 0)
continue
except ValueError:
# Interesting undefined symbol
undefined.add(name)
print("\nFinding references to each undefined symbol")
def referencing_nodes(kconf, name):
# Returns a list of all menu nodes that reference a symbol named 'name' in
# any of their properties or property conditions
res = []
for node in kconf.node_iter():
for ref in node.referenced:
if ref.name == name:
res.append(node)
return res
# Maps each globally undefined symbol to the menu nodes that reference it
undef_sym_refs = [(name, set()) for name in undefined - defined]
for kconf in all_arch_srcarch_kconfigs():
for name, refs in undef_sym_refs:
# This means that we search the entire configuration tree for each
# undefined symbol, which is terribly inefficient. We could speed
# things up by tweaking referencing_nodes() to compare each symbol to
# multiple symbols while walking the configuration tree.
for node in referencing_nodes(kconf, name):
refs.add("{}:{}".format(node.filename, node.linenr))
print("\nThe following globally undefined symbols were found, listed here\n"
"together with the locations of the items that reference them.\n"
"References might come from enclosing menus and ifs.\n")
for name, refs in undef_sym_refs:
print(" {}: {}".format(name, ", ".join(refs)))