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