The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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""" |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 12 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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 = '' |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 22 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 23 | while True: |
| 24 | # Look for a section header |
| 25 | result = headerPattern.search(buffer, start) |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 26 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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()] |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 37 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 38 | sectionName = result.group(1) |
| 39 | start = result.end() |
| 40 | anchor = start |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 41 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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.""" |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 47 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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) |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 59 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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.""" |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 71 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 72 | start = 0 |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 73 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 74 | while True: |
| 75 | # Find the next reference to the method signature |
| 76 | match = codes.find(method, start) |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 77 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 78 | if match is -1: |
| 79 | break; |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 80 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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 |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 89 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 90 | start = match + len(method) |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 91 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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 |
Carl Shapiro | de75089 | 2010-06-08 16:37:12 -0700 | [diff] [blame] | 123 | |
The Android Open Source Project | f6c3871 | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 124 | if count is 0: |
| 125 | print "\tNone" |
| 126 | |
| 127 | if __name__ == '__main__': |
| 128 | main() |