blob: eb71b7c24fe9eaf9d8339d611b03ef2bcddfe114 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001#!/usr/bin/env python
2
3import os
4import re
5import sys
6
7def SplitSections(buffer):
8 """Spin through the input buffer looking for section header lines.
9 When found, the name of the section is extracted. The entire contents
10 of that section is added to a result hashmap with the section name
11 as the key"""
12
13 # Match lines like
14 # |section_name:
15 # capturing section_name
16 headerPattern = re.compile(r'^\s+\|([a-z _]+)\:$', re.MULTILINE)
17
18 sections = {}
19 start = 0
20 anchor = -1
21 sectionName = ''
22
23 while True:
24 # Look for a section header
25 result = headerPattern.search(buffer, start)
26
27 # If there are no more, add a section from the last header to EOF
28 if result is None:
29 if anchor is not -1:
30 sections[sectionName] = buffer[anchor]
31 return sections
32
33 # Add the lines from the last header, to this one to the sections
34 # map indexed by the section name
35 if anchor is not -1:
36 sections[sectionName] = buffer[anchor:result.start()]
37
38 sectionName = result.group(1)
39 start = result.end()
40 anchor = start
41
42 return sections
43
44def FindMethods(section):
45 """Spin through the 'method code index' section and extract all
46 method signatures. When found, they are added to a result list."""
47
48 # Match lines like:
49 # |[abcd] com/example/app/Class.method:(args)return
50 # capturing the method signature
51 methodPattern = re.compile(r'^\s+\|\[\w{4}\] (.*)$', re.MULTILINE)
52
53 start = 0
54 methods = []
55
56 while True:
57 # Look for a method name
58 result = methodPattern.search(section, start)
59
60 if result is None:
61 return methods
62
63 # Add the captured signature to the method list
64 methods.append(result.group(1))
65 start = result.end()
66
67def CallsMethod(codes, method):
68 """Spin through all the input method signatures. For each one, return
69 whether or not there is method invokation line in the codes section that
70 lists the method as the target."""
71
72 start = 0
73
74 while True:
75 # Find the next reference to the method signature
76 match = codes.find(method, start)
77
78 if match is -1:
79 break;
80
81 # Find the beginning of the line the method reference is on
82 startOfLine = codes.rfind("\n", 0, match) + 1
83
84 # If the word 'invoke' comes between the beginning of the line
85 # and the method reference, then it is a call to that method rather
86 # than the beginning of the code section for that method.
87 if codes.find("invoke", startOfLine, match) is not -1:
88 return True
89
90 start = match + len(method)
91
92 return False
93
94
95
96def main():
97 if len(sys.argv) is not 2 or not sys.argv[1].endswith(".jar"):
98 print "Usage:", sys.argv[0], "<filename.jar>"
99 sys.exit()
100
101 command = 'dx --dex --dump-width=1000 --dump-to=-"" "%s"' % sys.argv[1]
102
103 pipe = os.popen(command)
104
105 # Read the whole dump file into memory
106 data = pipe.read()
107 sections = SplitSections(data)
108
109 pipe.close()
110 del(data)
111
112 methods = FindMethods(sections['method code index'])
113 codes = sections['codes']
114 del(sections)
115
116 print "Dead Methods:"
117 count = 0
118
119 for method in methods:
120 if not CallsMethod(codes, method):
121 print "\t", method
122 count += 1
123
124 if count is 0:
125 print "\tNone"
126
127if __name__ == '__main__':
128 main()