home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 14 / hacker14.iso / programacao / pythonwin / python.exe / OBJGRAPH.PY < prev    next >
Encoding:
Python Source  |  2003-05-13  |  6.1 KB  |  215 lines

  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 regex
  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 = regex.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. try:
  212.     sys.exit(main())
  213. except KeyboardInterrupt:
  214.     sys.exit(1)
  215.