summaryrefslogtreecommitdiff
path: root/examples/find_symbol.py
blob: 0d3c96869e1886e020419845fafa9d2aa1638259 (plain)
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
# Prints all menu nodes that reference a given symbol any of their properties
# or property conditions, along with their parent menu nodes.
#
# Usage:
#
#   $ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/examples/find_symbol.py SCRIPT_ARG=<name>
#
# Example output for SCRIPT_ARG=X86:
#
#   Found 470 locations that reference X86:
#
#   ========== Location 1 (init/Kconfig:1108) ==========
#
#   config SGETMASK_SYSCALL
#   	bool
#   	prompt "sgetmask/ssetmask syscalls support" if EXPERT
#   	default PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
#   	help
#   	  sys_sgetmask and sys_ssetmask are obsolete system calls
#   	  no longer supported in libc but still enabled by default in some
#   	  architectures.
#
#   	  If unsure, leave the default option here.
#
#   ---------- Parent 1 (init/Kconfig:1077)  ----------
#
#   menuconfig EXPERT
#   	bool
#   	prompt "Configure standard kernel features (expert users)"
#   	select DEBUG_KERNEL
#   	help
#   	  This option allows certain base kernel options and settings
#   	  to be disabled or tweaked. This is for specialized
#   	  environments which can tolerate a "non-standard" kernel.
#   	  Only use this if you really know what you are doing.
#
#   ---------- Parent 2 (init/Kconfig:39)  ----------
#
#   menu "General setup"
#
#   ========== Location 2 (arch/Kconfig:29) ==========
#
#   config OPROFILE_EVENT_MULTIPLEX
#   	bool
#   	prompt "OProfile multiplexing support (EXPERIMENTAL)" if OPROFILE && X86
#   	default "n" if OPROFILE && X86
#   	depends on OPROFILE && X86
#   	help
#   	  The number of hardware counters is limited. The multiplexing
#   	  feature enables OProfile to gather more events than counters
#   	  are provided by the hardware. This is realized by switching
#   	  between events at a user specified time interval.
#
#   	  If unsure, say N.
#
#   ---------- Parent 1 (arch/Kconfig:16)  ----------
#
#   config OPROFILE
#   	tristate
#   	prompt "OProfile system profiling" if PROFILING && HAVE_OPROFILE
#   	select RING_BUFFER if PROFILING && HAVE_OPROFILE
#   	select RING_BUFFER_ALLOW_SWAP if PROFILING && HAVE_OPROFILE
#   	depends on PROFILING && HAVE_OPROFILE
#   	help
#   	  OProfile is a profiling system capable of profiling the
#   	  whole system, include the kernel, kernel modules, libraries,
#   	  and applications.
#
#   	  If unsure, say N.
#
#   ---------- Parent 2 (init/Kconfig:39)  ----------
#
#   menu "General setup"
#
#   ... (tons more)

import sys

import kconfiglib


def referencing_nodes(node, sym):
    # Returns a list of all menu nodes that reference 'sym' in any of their
    # properties or property conditions

    res = []

    while node:
        if sym in node.referenced:
            res.append(node)

        if node.list:
            res.extend(referencing_nodes(node.list, sym))

        node = node.next

    return res


if len(sys.argv) < 3:
    sys.exit('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=<name>')

kconf = kconfiglib.Kconfig(sys.argv[1])
sym_name = sys.argv[2]

if sym_name not in kconf.syms:
    print("No symbol {} exists in the configuration".format(sym_name))
    sys.exit(0)

nodes = referencing_nodes(kconf.top_node, kconf.syms[sym_name])
if not nodes:
    print("No reference to {} found".format(sym_name))
    sys.exit(0)

print("Found {} locations that reference {}:\n"
      .format(len(nodes), sym_name))

for i, node in enumerate(nodes, 1):
    print("========== Location {} ({}:{}) ==========\n\n{}"
          .format(i, node.filename, node.linenr, node))

    # Print the parents of the menu node too

    node = node.parent
    parent_i = 1
    while node is not kconf.top_node:
        print("---------- Parent {} ({}:{})  ----------\n\n{}"
              .format(parent_i, node.filename, node.linenr, node))
        node = node.parent
        parent_i += 1