1#!/usr/bin/env python 2# 3# Copyright (C) 2013 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""stack symbolizes native crash dumps.""" 18 19import getopt 20import glob 21import os 22import sys 23 24import stack_core 25import subprocess 26import symbol 27import sys 28 29DEFAULT_SYMROOT='/tmp/symbols' 30 31def PrintUsage(): 32 """Print usage and exit with error.""" 33 # pylint: disable-msg=C6310 34 print 35 print " usage: " + sys.argv[0] + " [options] [FILE]" 36 print 37 print " --symbols-dir=path" 38 print " the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols" 39 print 40 print " --chrome-symbols-dir=path" 41 print " the path to a Chrome symbols dir (can be absolute or relative" 42 print " to src), such as =out/Debug/lib" 43 print " If not specified, will look for the newest lib in out/Debug or" 44 print " out/Release" 45 print 46 print " --symbols-zip=path" 47 print " the path to a symbols zip file, such as =dream-symbols-12345.zip" 48 print 49 print " --more-info" 50 print " --less-info" 51 print " Change the level of detail in the output." 52 print " --more-info is slower and more verbose, but more functions will" 53 print " be fully qualified with namespace/classname and have full" 54 print " argument information. Also, the 'stack data' section will be" 55 print " printed." 56 print 57 print " --arch=arm|arm64|x86_64|x86|mips" 58 print " the target architecture" 59 print 60 print " FILE should contain a stack trace in it somewhere" 61 print " the tool will find that and re-print it with" 62 print " source files and line numbers. If you don't" 63 print " pass FILE, or if file is -, it reads from" 64 print " stdin." 65 print 66 # pylint: enable-msg=C6310 67 sys.exit(1) 68 69def UnzipSymbols(symbolfile, symdir=None): 70 """Unzips a file to DEFAULT_SYMROOT and returns the unzipped location. 71 72 Args: 73 symbolfile: The .zip file to unzip 74 symdir: Optional temporary directory to use for extraction 75 76 Returns: 77 A tuple containing (the directory into which the zip file was unzipped, 78 the path to the "symbols" directory in the unzipped file). To clean 79 up, the caller can delete the first element of the tuple. 80 81 Raises: 82 SymbolDownloadException: When the unzip fails. 83 """ 84 if not symdir: 85 symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(symbolfile)) 86 if not os.path.exists(symdir): 87 os.makedirs(symdir) 88 89 print "extracting %s..." % symbolfile 90 saveddir = os.getcwd() 91 os.chdir(symdir) 92 try: 93 unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile]) 94 if unzipcode > 0: 95 os.remove(symbolfile) 96 raise SymbolDownloadException("failed to extract symbol files (%s)." 97 % symbolfile) 98 finally: 99 os.chdir(saveddir) 100 101 android_symbols = glob.glob("%s/out/target/product/*/symbols" % symdir) 102 if android_symbols: 103 return (symdir, android_symbols[0]) 104 else: 105 # This is a zip of Chrome symbols, so symbol.CHROME_SYMBOLS_DIR needs to be 106 # updated to point here. 107 symbol.CHROME_SYMBOLS_DIR = symdir 108 return (symdir, symdir) 109 110 111def main(): 112 try: 113 options, arguments = getopt.getopt(sys.argv[1:], "", 114 ["more-info", 115 "less-info", 116 "chrome-symbols-dir=", 117 "symbols-dir=", 118 "symbols-zip=", 119 "arch=", 120 "help"]) 121 except getopt.GetoptError, unused_error: 122 PrintUsage() 123 124 zip_arg = None 125 more_info = False 126 for option, value in options: 127 if option == "--help": 128 PrintUsage() 129 elif option == "--symbols-dir": 130 symbol.SYMBOLS_DIR = os.path.expanduser(value) 131 elif option == "--symbols-zip": 132 zip_arg = os.path.expanduser(value) 133 elif option == "--arch": 134 symbol.ARCH = value 135 elif option == "--chrome-symbols-dir": 136 symbol.CHROME_SYMBOLS_DIR = os.path.join(symbol.CHROME_SYMBOLS_DIR, value) 137 elif option == "--more-info": 138 more_info = True 139 elif option == "--less-info": 140 more_info = False 141 142 if len(arguments) > 1: 143 PrintUsage() 144 145 if not arguments or arguments[0] == "-": 146 print "Reading native crash info from stdin" 147 f = sys.stdin 148 else: 149 print "Searching for native crashes in %s" % arguments[0] 150 f = open(arguments[0], "r") 151 152 lines = f.readlines() 153 f.close() 154 155 rootdir = None 156 if zip_arg: 157 rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg) 158 159 print "Reading Android symbols from", symbol.SYMBOLS_DIR 160 print "Reading Chrome symbols from", symbol.CHROME_SYMBOLS_DIR 161 stack_core.ConvertTrace(lines, more_info) 162 163 if rootdir: 164 # be a good citizen and clean up...os.rmdir and os.removedirs() don't work 165 cmd = "rm -rf \"%s\"" % rootdir 166 print "\ncleaning up (%s)" % cmd 167 os.system(cmd) 168 169if __name__ == "__main__": 170 main() 171 172# vi: ts=2 sw=2 173