symbian-qemu-0.9.1-12/python-win32-2.6.1/Tools/Scripts/objgraph.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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)