home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Demo / scripts / objgraph.py < prev    next >
Text File  |  1992-12-09  |  5KB  |  216 lines

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