text: #!/usr/bin/env python
  
  import os
  import re
  import sys
  
  def SplitSections(buffer):
      """Spin through the input buffer looking for section header lines.
      When found, the name of the section is extracted.  The entire contents
      of that section is added to a result hashmap with the section name
      as the key"""
  
      # Match lines like
      #              |section_name:
      # capturing section_name
      headerPattern = re.compile(r'^\s+\|([a-z _]+)\:$', re.MULTILINE)
  
      sections = {}
      start = 0
      anchor = -1
      sectionName = ''
  
      while True:
          # Look for a section header
          result = headerPattern.search(buffer, start)
  
          # If there are no more, add a section from the last header to EOF
          if result is None:
              if anchor is not -1:
                  sections[sectionName] = buffer[anchor]
              return sections
  
          # Add the lines from the last header, to this one to the sections
          # map indexed by the section name
          if anchor is not -1:
              sections[sectionName] = buffer[anchor:result.start()]
  
          sectionName = result.group(1)
          start = result.end()
          anchor = start
  
      return sections
  
  def FindMethods(section):
      """Spin through the 'method code index' section and extract all
      method signatures.  When found, they are added to a result list."""
  
      # Match lines like:
      #             |[abcd] com/example/app/Class.method:(args)return
      # capturing the method signature
      methodPattern = re.compile(r'^\s+\|\[\w{4}\] (.*)$', re.MULTILINE)
  
      start = 0
      methods = []
  
      while True:
          # Look for a method name
          result = methodPattern.search(section, start)
  
          if result is None:
              return methods
  
          # Add the captured signature to the method list
          methods.append(result.group(1))
          start = result.end()
  
  def CallsMethod(codes, method):
      """Spin through all the input method signatures.  For each one, return
      whether or not there is method invokation line in the codes section that
      lists the method as the target."""
  
      start = 0
  
      while True:
          # Find the next reference to the method signature
          match = codes.find(method, start)
  
          if match is -1:
              break;
  
          # Find the beginning of the line the method reference is on
          startOfLine = codes.rfind("\n", 0, match) + 1
  
          # If the word 'invoke' comes between the beginning of the line
          # and the method reference, then it is a call to that method rather
          # than the beginning of the code section for that method.
          if codes.find("invoke", startOfLine, match) is not -1:
              return True
  
          start = match + len(method)
  
      return False
  
  
  
  def main():
      if len(sys.argv) is not 2 or not sys.argv[1].endswith(".jar"):
          print "Usage:", sys.argv[0], "<filename.jar>"
          sys.exit()
  
      command = 'dx --dex --dump-width=1000 --dump-to=-"" "%s"' % sys.argv[1]
  
      pipe = os.popen(command)
  
      # Read the whole dump file into memory
      data = pipe.read()
      sections = SplitSections(data)
  
      pipe.close()
      del(data)
  
      methods = FindMethods(sections['method code index'])
      codes = sections['codes']
      del(sections)
  
      print "Dead Methods:"
      count = 0
  
      for method in methods:
          if not CallsMethod(codes, method):
              print "\t", method
              count += 1
  
      if count is 0:
          print "\tNone"
  
  if __name__ == '__main__':
      main()
  