ยปCore Development>Code coverage>Tools/scripts/objgraph.py

Python code coverage for Tools/scripts/objgraph.py

#countcontent
1n/a#! /usr/bin/env python3
2n/a
3n/a# objgraph
4n/a#
5n/a# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules
6n/a# and print various interesting listings, such as:
7n/a#
8n/a# - which names are used but not defined in the set (and used where),
9n/a# - which names are defined in the set (and where),
10n/a# - which modules use which other modules,
11n/a# - which modules are used by which other modules.
12n/a#
13n/a# Usage: objgraph [-cdu] [file] ...
14n/a# -c: print callers per objectfile
15n/a# -d: print callees per objectfile
16n/a# -u: print usage of undefined symbols
17n/a# If none of -cdu is specified, all are assumed.
18n/a# Use "nm -o" to generate the input (on IRIX: "nm -Bo"),
19n/a# e.g.: nm -o /lib/libc.a | objgraph
20n/a
21n/a
22n/aimport sys
23n/aimport os
24n/aimport getopt
25n/aimport re
26n/a
27n/a# Types of symbols.
28n/a#
29n/adefinitions = 'TRGDSBAEC'
30n/aexternals = 'UV'
31n/aignore = 'Nntrgdsbavuc'
32n/a
33n/a# Regular expression to parse "nm -o" output.
34n/a#
35n/amatcher = re.compile('(.*):\t?........ (.) (.*)$')
36n/a
37n/a# Store "item" in "dict" under "key".
38n/a# The dictionary maps keys to lists of items.
39n/a# If there is no list for the key yet, it is created.
40n/a#
41n/adef store(dict, key, item):
42n/a if key in dict:
43n/a dict[key].append(item)
44n/a else:
45n/a dict[key] = [item]
46n/a
47n/a# Return a flattened version of a list of strings: the concatenation
48n/a# of its elements with intervening spaces.
49n/a#
50n/adef flat(list):
51n/a s = ''
52n/a for item in list:
53n/a s = s + ' ' + item
54n/a return s[1:]
55n/a
56n/a# Global variables mapping defined/undefined names to files and back.
57n/a#
58n/afile2undef = {}
59n/adef2file = {}
60n/afile2def = {}
61n/aundef2file = {}
62n/a
63n/a# Read one input file and merge the data into the tables.
64n/a# Argument is an open file.
65n/a#
66n/adef readinput(fp):
67n/a while 1:
68n/a s = fp.readline()
69n/a if not s:
70n/a break
71n/a # If you get any output from this line,
72n/a # it is probably caused by an unexpected input line:
73n/a if matcher.search(s) < 0: s; continue # Shouldn't happen
74n/a (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4]
75n/a fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b]
76n/a if type in definitions:
77n/a store(def2file, name, fn)
78n/a store(file2def, fn, name)
79n/a elif type in externals:
80n/a store(file2undef, fn, name)
81n/a store(undef2file, name, fn)
82n/a elif not type in ignore:
83n/a print(fn + ':' + name + ': unknown type ' + type)
84n/a
85n/a# Print all names that were undefined in some module and where they are
86n/a# defined.
87n/a#
88n/adef printcallee():
89n/a flist = sorted(file2undef.keys())
90n/a for filename in flist:
91n/a print(filename + ':')
92n/a elist = file2undef[filename]
93n/a elist.sort()
94n/a for ext in elist:
95n/a if len(ext) >= 8:
96n/a tabs = '\t'
97n/a else:
98n/a tabs = '\t\t'
99n/a if ext not in def2file:
100n/a print('\t' + ext + tabs + ' *undefined')
101n/a else:
102n/a print('\t' + ext + tabs + flat(def2file[ext]))
103n/a
104n/a# Print for each module the names of the other modules that use it.
105n/a#
106n/adef printcaller():
107n/a files = sorted(file2def.keys())
108n/a for filename in files:
109n/a callers = []
110n/a for label in file2def[filename]:
111n/a if label in undef2file:
112n/a callers = callers + undef2file[label]
113n/a if callers:
114n/a callers.sort()
115n/a print(filename + ':')
116n/a lastfn = ''
117n/a for fn in callers:
118n/a if fn != lastfn:
119n/a print('\t' + fn)
120n/a lastfn = fn
121n/a else:
122n/a print(filename + ': unused')
123n/a
124n/a# Print undefined names and where they are used.
125n/a#
126n/adef printundef():
127n/a undefs = {}
128n/a for filename in list(file2undef.keys()):
129n/a for ext in file2undef[filename]:
130n/a if ext not in def2file:
131n/a store(undefs, ext, filename)
132n/a elist = sorted(undefs.keys())
133n/a for ext in elist:
134n/a print(ext + ':')
135n/a flist = sorted(undefs[ext])
136n/a for filename in flist:
137n/a print('\t' + filename)
138n/a
139n/a# Print warning messages about names defined in more than one file.
140n/a#
141n/adef warndups():
142n/a savestdout = sys.stdout
143n/a sys.stdout = sys.stderr
144n/a names = sorted(def2file.keys())
145n/a for name in names:
146n/a if len(def2file[name]) > 1:
147n/a print('warning:', name, 'multiply defined:', end=' ')
148n/a print(flat(def2file[name]))
149n/a sys.stdout = savestdout
150n/a
151n/a# Main program
152n/a#
153n/adef main():
154n/a try:
155n/a optlist, args = getopt.getopt(sys.argv[1:], 'cdu')
156n/a except getopt.error:
157n/a sys.stdout = sys.stderr
158n/a print('Usage:', os.path.basename(sys.argv[0]), end=' ')
159n/a print('[-cdu] [file] ...')
160n/a print('-c: print callers per objectfile')
161n/a print('-d: print callees per objectfile')
162n/a print('-u: print usage of undefined symbols')
163n/a print('If none of -cdu is specified, all are assumed.')
164n/a print('Use "nm -o" to generate the input (on IRIX: "nm -Bo"),')
165n/a print('e.g.: nm -o /lib/libc.a | objgraph')
166n/a return 1
167n/a optu = optc = optd = 0
168n/a for opt, void in optlist:
169n/a if opt == '-u':
170n/a optu = 1
171n/a elif opt == '-c':
172n/a optc = 1
173n/a elif opt == '-d':
174n/a optd = 1
175n/a if optu == optc == optd == 0:
176n/a optu = optc = optd = 1
177n/a if not args:
178n/a args = ['-']
179n/a for filename in args:
180n/a if filename == '-':
181n/a readinput(sys.stdin)
182n/a else:
183n/a readinput(open(filename, 'r'))
184n/a #
185n/a warndups()
186n/a #
187n/a more = (optu + optc + optd > 1)
188n/a if optd:
189n/a if more:
190n/a print('---------------All callees------------------')
191n/a printcallee()
192n/a if optu:
193n/a if more:
194n/a print('---------------Undefined callees------------')
195n/a printundef()
196n/a if optc:
197n/a if more:
198n/a print('---------------All Callers------------------')
199n/a printcaller()
200n/a return 0
201n/a
202n/a# Call the main program.
203n/a# Use its return value as exit status.
204n/a# Catch interrupts to avoid stack trace.
205n/a#
206n/aif __name__ == '__main__':
207n/a try:
208n/a sys.exit(main())
209n/a except KeyboardInterrupt:
210n/a sys.exit(1)