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