OSDN Git Service

am 0ff6a7cf: am aa09711b: am 2b9e8c1d: Modify dex-preopt to take better arguments...
[android-x86/dalvik.git] / tools / deadcode.py
1 #!/usr/bin/env python
2
3 import os
4 import re
5 import sys
6
7 def 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
44 def 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
67 def 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
96 def 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
127 if __name__ == '__main__':
128     main()