~malept/ubuntu/lucid/python2.6/dev-dependency-fix

« back to all changes in this revision

Viewing changes to Tools/scripts/objgraph.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-02-13 12:51:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090213125100-uufgcb9yeqzujpqw
Tags: upstream-2.6.1
ImportĀ upstreamĀ versionĀ 2.6.1

Show diffs side-by-side

added added

removed removed

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