OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 # pylint: disable=too-many-lines | 5 # pylint: disable=too-many-lines |
6 | 6 |
7 """ | 7 """ |
8 This script processes trace files and symbolizes stack frames generated by | 8 This script processes trace files and symbolizes stack frames generated by |
9 Chrome's native heap profiler. This script assumes that the Chrome binary | 9 Chrome's native heap profiler. This script assumes that the Chrome binary |
10 referenced in the trace contains symbols, and is the same binary used to emit | 10 referenced in the trace contains symbols, and is the same binary used to emit |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 os.path.join(os.path.dirname(__file__), '..', '..', '..')) | 230 os.path.join(os.path.dirname(__file__), '..', '..', '..')) |
231 | 231 |
232 _SYMBOLS_PATH = os.path.abspath(os.path.join( | 232 _SYMBOLS_PATH = os.path.abspath(os.path.join( |
233 _TRACING_DIR, | 233 _TRACING_DIR, |
234 'third_party', | 234 'third_party', |
235 'symbols')) | 235 'symbols')) |
236 sys.path.append(_SYMBOLS_PATH) | 236 sys.path.append(_SYMBOLS_PATH) |
237 # pylint: disable=import-error | 237 # pylint: disable=import-error |
238 import symbols.elf_symbolizer as elf_symbolizer | 238 import symbols.elf_symbolizer as elf_symbolizer |
239 | 239 |
240 from . import symbolize_trace_atos_regex | 240 from tracing.extras.symbolizer import symbolize_trace_atos_regex |
241 from . import symbolize_trace_macho_reader | 241 from tracing.extras.symbolizer import symbolize_trace_macho_reader |
242 | 242 |
243 _PY_UTILS_PATH = os.path.abspath(os.path.join( | 243 _PY_UTILS_PATH = os.path.abspath(os.path.join( |
244 _TRACING_DIR, | 244 _TRACING_DIR, |
245 '..', | 245 '..', |
246 'common', | 246 'common', |
247 'py_utils')) | 247 'py_utils')) |
248 sys.path.append(_PY_UTILS_PATH) | 248 sys.path.append(_PY_UTILS_PATH) |
249 # pylint: disable=import-error | 249 # pylint: disable=import-error |
250 import py_utils.cloud_storage as cloud_storage | 250 import py_utils.cloud_storage as cloud_storage |
251 | 251 |
| 252 _UNNAMED_FILE = 'unnamed' |
| 253 |
| 254 |
252 class NodeWrapper(object): | 255 class NodeWrapper(object): |
253 """Wraps an event data node(s). | 256 """Wraps an event data node(s). |
254 | 257 |
255 A node is a reference into a trace event JSON. Wrappers parse nodes to | 258 A node is a reference into a trace event JSON. Wrappers parse nodes to |
256 provide convenient APIs and update nodes when asked to propagate changes | 259 provide convenient APIs and update nodes when asked to propagate changes |
257 back (see ApplyModifications() below). | 260 back (see ApplyModifications() below). |
258 | 261 |
259 Here is an example of legacy metadata event that contains stack frame tree: | 262 Here is an example of legacy metadata event that contains stack frame tree: |
260 | 263 |
261 { | 264 { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 }, | 313 }, |
311 ... | 314 ... |
312 ] | 315 ] |
313 } | 316 } |
314 """ | 317 """ |
315 | 318 |
316 class Region(object): | 319 class Region(object): |
317 def __init__(self, start_address, size, file_path): | 320 def __init__(self, start_address, size, file_path): |
318 self._start_address = start_address | 321 self._start_address = start_address |
319 self._size = size | 322 self._size = size |
320 self._file_path = file_path | 323 self._file_path = file_path if file_path else _UNNAMED_FILE |
321 | 324 |
322 @property | 325 @property |
323 def start_address(self): | 326 def start_address(self): |
324 return self._start_address | 327 return self._start_address |
325 | 328 |
326 @property | 329 @property |
327 def end_address(self): | 330 def end_address(self): |
328 return self._start_address + self._size | 331 return self._start_address + self._size |
329 | 332 |
330 @property | 333 @property |
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 """Holds file path, addresses to symbolize and stack frames to update. | 982 """Holds file path, addresses to symbolize and stack frames to update. |
980 | 983 |
981 This class is a link between ELFSymbolizer and a trace file: it specifies | 984 This class is a link between ELFSymbolizer and a trace file: it specifies |
982 what to symbolize (addresses) and what to update with the symbolization | 985 what to symbolize (addresses) and what to update with the symbolization |
983 result (frames). | 986 result (frames). |
984 """ | 987 """ |
985 def __init__(self, file_path): | 988 def __init__(self, file_path): |
986 self.path = file_path | 989 self.path = file_path |
987 self.symbolizable_path = file_path # path to use for symbolization | 990 self.symbolizable_path = file_path # path to use for symbolization |
988 self.frames_by_address = collections.defaultdict(list) | 991 self.frames_by_address = collections.defaultdict(list) |
| 992 self.skip_symbolization = False |
989 | 993 |
990 | 994 |
991 def ResolveSymbolizableFiles(processes): | 995 def ResolveSymbolizableFiles(processes): |
992 """Resolves and groups PCs into list of SymbolizableFiles. | 996 """Resolves and groups PCs into list of SymbolizableFiles. |
993 | 997 |
994 As part of the grouping process, this function resolves PC from each stack | 998 As part of the grouping process, this function resolves PC from each stack |
995 frame to the corresponding mmap region. Stack frames that failed to resolve | 999 frame to the corresponding mmap region. Stack frames that failed to resolve |
996 are symbolized with '<unresolved>'. | 1000 are symbolized with '<unresolved>'. |
997 """ | 1001 """ |
998 symfile_by_path = {} | 1002 symfile_by_path = {} |
999 for process in processes: | 1003 for process in processes: |
1000 if not process.memory_map: | 1004 if not process.memory_map: |
1001 continue | 1005 continue |
1002 for frame in process.stack_frame_map.frame_by_id.itervalues(): | 1006 for frame in process.stack_frame_map.frame_by_id.itervalues(): |
1003 if frame.pc is None: | 1007 if frame.pc is None: |
1004 continue | 1008 continue |
1005 region = process.memory_map.FindRegion(frame.pc) | 1009 region = process.memory_map.FindRegion(frame.pc) |
1006 if region is None: | 1010 if region is None: |
1007 frame.name = '<unresolved>' | 1011 frame.name = '<unresolved>' |
1008 continue | 1012 continue |
1009 | 1013 |
1010 symfile = symfile_by_path.get(region.file_path) | 1014 symfile = symfile_by_path.get(region.file_path) |
1011 if symfile is None: | 1015 if symfile is None: |
1012 symfile = SymbolizableFile(region.file_path) | 1016 file_path = region.file_path |
| 1017 symfile = SymbolizableFile(file_path) |
1013 symfile_by_path[symfile.path] = symfile | 1018 symfile_by_path[symfile.path] = symfile |
1014 | 1019 |
1015 relative_pc = frame.pc - region.start_address | 1020 relative_pc = frame.pc - region.start_address |
1016 symfile.frames_by_address[relative_pc].append(frame) | 1021 symfile.frames_by_address[relative_pc].append(frame) |
1017 return symfile_by_path.values() | 1022 return symfile_by_path.values() |
1018 | 1023 |
1019 | 1024 |
1020 def FindInSystemPath(binary_name): | 1025 def FindInSystemPath(binary_name): |
1021 paths = os.environ['PATH'].split(os.pathsep) | 1026 paths = os.environ['PATH'].split(os.pathsep) |
1022 for path in paths: | 1027 for path in paths: |
(...skipping 11 matching lines...) Expand all Loading... |
1034 self.is_win = sys.platform == 'win32' | 1039 self.is_win = sys.platform == 'win32' |
1035 if self.is_mac: | 1040 if self.is_mac: |
1036 self.binary = 'atos' | 1041 self.binary = 'atos' |
1037 self._matcher = symbolize_trace_atos_regex.AtosRegexMatcher() | 1042 self._matcher = symbolize_trace_atos_regex.AtosRegexMatcher() |
1038 elif self.is_win: | 1043 elif self.is_win: |
1039 self.binary = 'addr2line-pdb.exe' | 1044 self.binary = 'addr2line-pdb.exe' |
1040 else: | 1045 else: |
1041 self.binary = 'addr2line' | 1046 self.binary = 'addr2line' |
1042 self.symbolizer_path = FindInSystemPath(self.binary) | 1047 self.symbolizer_path = FindInSystemPath(self.binary) |
1043 | 1048 |
1044 def _SymbolizeLinuxAndAndroid(self, symfile, unsymbolized_name): | 1049 def _SymbolizeLinuxAndAndroid(self, symfile): |
1045 def _SymbolizerCallback(sym_info, frames): | 1050 def _SymbolizerCallback(sym_info, frames): |
1046 # Unwind inline chain to the top. | 1051 # Unwind inline chain to the top. |
1047 while sym_info.inlined_by: | 1052 while sym_info.inlined_by: |
1048 sym_info = sym_info.inlined_by | 1053 sym_info = sym_info.inlined_by |
1049 | 1054 |
1050 symbolized_name = sym_info.name if sym_info.name else unsymbolized_name | 1055 symbolized_name = (sym_info.name if sym_info.name else |
| 1056 '<{}>'.format(symfile.path)) |
1051 for frame in frames: | 1057 for frame in frames: |
1052 frame.name = symbolized_name | 1058 frame.name = symbolized_name |
1053 | 1059 |
1054 symbolizer = elf_symbolizer.ELFSymbolizer(symfile.symbolizable_path, | 1060 symbolizer = elf_symbolizer.ELFSymbolizer(symfile.symbolizable_path, |
1055 self.symbolizer_path, | 1061 self.symbolizer_path, |
1056 _SymbolizerCallback, | 1062 _SymbolizerCallback, |
1057 inlines=True) | 1063 inlines=True) |
1058 | 1064 |
1059 for address, frames in symfile.frames_by_address.iteritems(): | 1065 for address, frames in symfile.frames_by_address.iteritems(): |
1060 # SymbolizeAsync() asserts that the type of address is int. We operate | 1066 # SymbolizeAsync() asserts that the type of address is int. We operate |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 stdout_data = stdout_data.split('\n') | 1120 stdout_data = stdout_data.split('\n') |
1115 | 1121 |
1116 # This is known to be in the same order as stderr_data. | 1122 # This is known to be in the same order as stderr_data. |
1117 for i, addr in enumerate(addrs): | 1123 for i, addr in enumerate(addrs): |
1118 for frame in symfile.frames_by_address[int(addr, 16)]: | 1124 for frame in symfile.frames_by_address[int(addr, 16)]: |
1119 # Output of addr2line with --functions is always 2 outputs per | 1125 # Output of addr2line with --functions is always 2 outputs per |
1120 # symbol, function name followed by source line number. Only grab | 1126 # symbol, function name followed by source line number. Only grab |
1121 # the function name as line info is not always available. | 1127 # the function name as line info is not always available. |
1122 frame.name = stdout_data[i * 2] | 1128 frame.name = stdout_data[i * 2] |
1123 | 1129 |
1124 def Symbolize(self, symfile, unsymbolized_name): | 1130 def SymbolizeSymfile(self, symfile): |
| 1131 if symfile.skip_symbolization: |
| 1132 for address, frames in symfile.frames_by_address.iteritems(): |
| 1133 unsymbolized_name = ('<' + os.path.basename(symfile.symbolizable_path) |
| 1134 + '>') |
| 1135 # Only append the address if there's a library. |
| 1136 if symfile.symbolizable_path != _UNNAMED_FILE: |
| 1137 unsymbolized_name += ' + ' + str(hex(address)) |
| 1138 |
| 1139 for frame in frames: |
| 1140 frame.name = unsymbolized_name |
| 1141 return |
| 1142 |
1125 if self.is_mac: | 1143 if self.is_mac: |
1126 self._SymbolizeMac(symfile) | 1144 self._SymbolizeMac(symfile) |
1127 elif self.is_win: | 1145 elif self.is_win: |
1128 self._SymbolizeWin(symfile) | 1146 self._SymbolizeWin(symfile) |
1129 else: | 1147 else: |
1130 self._SymbolizeLinuxAndAndroid(symfile, unsymbolized_name) | 1148 self._SymbolizeLinuxAndAndroid(symfile) |
1131 | 1149 |
1132 def IsSymbolizableFile(self, file_path): | 1150 def IsSymbolizableFile(self, file_path): |
1133 if self.is_win: | 1151 if self.is_win: |
1134 extension = os.path.splitext(file_path)[1].lower() | 1152 extension = os.path.splitext(file_path)[1].lower() |
1135 return extension in ['.dll', '.exe'] | 1153 return extension in ['.dll', '.exe'] |
1136 else: | 1154 else: |
1137 result = subprocess.check_output(['file', '-0', file_path]) | 1155 result = subprocess.check_output(['file', '-0', file_path]) |
1138 type_string = result[result.find('\0') + 1:] | 1156 type_string = result[result.find('\0') + 1:] |
1139 return bool(re.match(r'.*(ELF|Mach-O) (32|64)-bit\b.*', | 1157 return bool(re.match(r'.*(ELF|Mach-O) (32|64)-bit\b.*', |
1140 type_string, re.DOTALL)) | 1158 type_string, re.DOTALL)) |
1141 | 1159 |
1142 | 1160 |
1143 def SymbolizeFiles(symfiles, symbolizer): | 1161 def SymbolizeFiles(symfiles, symbolizer): |
1144 """Symbolizes each file in the given list of SymbolizableFiles | 1162 """Symbolizes each file in the given list of SymbolizableFiles |
1145 and updates stack frames with symbolization results.""" | 1163 and updates stack frames with symbolization results.""" |
1146 | 1164 |
1147 if not symfiles: | 1165 if not symfiles: |
1148 print 'Nothing to symbolize.' | 1166 print 'Nothing to symbolize.' |
1149 return | 1167 return |
1150 | 1168 |
1151 print 'Symbolizing...' | 1169 print 'Symbolizing...' |
1152 | 1170 |
1153 def _SubPrintf(message, *args): | 1171 def _SubPrintf(message, *args): |
1154 print (' ' + message).format(*args) | 1172 print (' ' + message).format(*args) |
1155 | 1173 |
1156 for symfile in symfiles: | 1174 for symfile in symfiles: |
1157 unsymbolized_name = '<{}>'.format( | |
1158 symfile.path if symfile.path else 'unnamed') | |
1159 | |
1160 problem = None | 1175 problem = None |
1161 if not os.path.isabs(symfile.symbolizable_path): | 1176 if not os.path.isabs(symfile.symbolizable_path): |
1162 problem = 'not a file' | 1177 problem = 'not a file' |
1163 elif not os.path.isfile(symfile.symbolizable_path): | 1178 elif not os.path.isfile(symfile.symbolizable_path): |
1164 problem = "file doesn't exist" | 1179 problem = "file doesn't exist" |
1165 elif not symbolizer.IsSymbolizableFile(symfile.symbolizable_path): | 1180 elif not symbolizer.IsSymbolizableFile(symfile.symbolizable_path): |
1166 problem = 'file is not symbolizable' | 1181 problem = 'file is not symbolizable' |
1167 if problem: | 1182 if problem: |
1168 _SubPrintf("Won't symbolize {} PCs for '{}': {}.", | 1183 _SubPrintf("Problem with '{}': {}.", |
1169 len(symfile.frames_by_address), | |
1170 symfile.symbolizable_path, | 1184 symfile.symbolizable_path, |
1171 problem) | 1185 problem) |
1172 for frames in symfile.frames_by_address.itervalues(): | 1186 symfile.skip_symbolization = True |
1173 for frame in frames: | |
1174 frame.name = unsymbolized_name | |
1175 continue | |
1176 | 1187 |
1177 _SubPrintf('Symbolizing {} PCs from {}...', | 1188 _SubPrintf('Symbolizing {} PCs from {}...', |
1178 len(symfile.frames_by_address), | 1189 len(symfile.frames_by_address), |
1179 symfile.symbolizable_path) | 1190 symfile.symbolizable_path) |
1180 | 1191 |
1181 symbolizer.Symbolize(symfile, unsymbolized_name) | 1192 symbolizer.SymbolizeSymfile(symfile) |
1182 | 1193 |
1183 | 1194 |
1184 # Matches Android library paths, supports both K (/data/app-lib/<>/lib.so) | 1195 # Matches Android library paths, supports both K (/data/app-lib/<>/lib.so) |
1185 # as well as L+ (/data/app/<>/lib/<>/lib.so). Library name is available | 1196 # as well as L+ (/data/app/<>/lib/<>/lib.so). Library name is available |
1186 # via 'name' group. | 1197 # via 'name' group. |
1187 ANDROID_PATH_MATCHER = re.compile( | 1198 ANDROID_PATH_MATCHER = re.compile( |
1188 r'^/data/(?:' | 1199 r'^/data/(?:' |
1189 r'app/[^/]+/lib/[^/]+/|' | 1200 r'app/[^/]+/lib/[^/]+/|' |
1190 r'app-lib/[^/]+/|' | 1201 r'app-lib/[^/]+/|' |
1191 r'data/[^/]+/incremental-install-files/lib/' | 1202 r'data/[^/]+/incremental-install-files/lib/' |
(...skipping 14 matching lines...) Expand all Loading... |
1206 name = match.group('name') | 1217 name = match.group('name') |
1207 symfile.symbolizable_path = os.path.join( | 1218 symfile.symbolizable_path = os.path.join( |
1208 output_path, ANDROID_UNSTRIPPED_SUBPATH, name) | 1219 output_path, ANDROID_UNSTRIPPED_SUBPATH, name) |
1209 else: | 1220 else: |
1210 # Clobber file path to trigger "not a file" problem in SymbolizeFiles(). | 1221 # Clobber file path to trigger "not a file" problem in SymbolizeFiles(). |
1211 # Without this, files won't be symbolized with "file not found" problem, | 1222 # Without this, files won't be symbolized with "file not found" problem, |
1212 # which is not accurate. | 1223 # which is not accurate. |
1213 symfile.symbolizable_path = 'android://{}'.format(symfile.path) | 1224 symfile.symbolizable_path = 'android://{}'.format(symfile.path) |
1214 | 1225 |
1215 | 1226 |
1216 def RemapMacFiles(symfiles, symbol_base_directory, version): | 1227 def RemapMacFiles(symfiles, symbol_base_directory, version, |
| 1228 only_symbolize_chrome_symbols): |
1217 suffix = ("Google Chrome Framework.dSYM/Contents/Resources/DWARF/" | 1229 suffix = ("Google Chrome Framework.dSYM/Contents/Resources/DWARF/" |
1218 "Google Chrome Framework") | 1230 "Google Chrome Framework") |
1219 symbol_sub_dir = os.path.join(symbol_base_directory, version) | 1231 symbol_sub_dir = os.path.join(symbol_base_directory, version) |
1220 symbolizable_path = os.path.join(symbol_sub_dir, suffix) | 1232 symbolizable_path = os.path.join(symbol_sub_dir, suffix) |
1221 | 1233 |
1222 for symfile in symfiles: | 1234 for symfile in symfiles: |
1223 if symfile.path.endswith("Google Chrome Framework"): | 1235 if symfile.path.endswith("Google Chrome Framework"): |
1224 symfile.symbolizable_path = symbolizable_path | 1236 symfile.symbolizable_path = symbolizable_path |
| 1237 elif only_symbolize_chrome_symbols: |
| 1238 symfile.skip_symbolization = True |
1225 | 1239 |
1226 def RemapWinFiles(symfiles, symbol_base_directory, version, is64bit): | 1240 def RemapWinFiles(symfiles, symbol_base_directory, version, is64bit, |
| 1241 only_symbolize_chrome_symbols): |
1227 folder = "win64" if is64bit else "win" | 1242 folder = "win64" if is64bit else "win" |
1228 symbol_sub_dir = os.path.join(symbol_base_directory, | 1243 symbol_sub_dir = os.path.join(symbol_base_directory, |
1229 "chrome-" + folder + "-" + version) | 1244 "chrome-" + folder + "-" + version) |
1230 for symfile in symfiles: | 1245 for symfile in symfiles: |
1231 image = os.path.join(symbol_sub_dir, os.path.basename(symfile.path)) | 1246 image = os.path.join(symbol_sub_dir, os.path.basename(symfile.path)) |
1232 symbols = image + ".pdb" | 1247 symbols = image + ".pdb" |
1233 if os.path.isfile(image) and os.path.isfile(symbols): | 1248 if os.path.isfile(image) and os.path.isfile(symbols): |
1234 symfile.symbolizable_path = image | 1249 symfile.symbolizable_path = image |
| 1250 elif only_symbolize_chrome_symbols: |
| 1251 symfile.skip_symbolization = True |
1235 | 1252 |
1236 def Symbolize(options, trace, symbolizer): | 1253 def SymbolizeTrace(options, trace, symbolizer): |
1237 symfiles = ResolveSymbolizableFiles(trace.processes) | 1254 symfiles = ResolveSymbolizableFiles(trace.processes) |
1238 | 1255 |
1239 # Android trace files don't have any indication they are from Android. | 1256 # Android trace files don't have any indication they are from Android. |
1240 # So we're checking for Android-specific paths. | 1257 # So we're checking for Android-specific paths. |
1241 if HaveFilesFromAndroid(symfiles): | 1258 if HaveFilesFromAndroid(symfiles): |
1242 if not options.output_directory: | 1259 if not options.output_directory: |
1243 sys.exit('The trace file appears to be from Android. Please ' | 1260 sys.exit('The trace file appears to be from Android. Please ' |
1244 'specify output directory to properly symbolize it.') | 1261 'specify output directory to properly symbolize it.') |
1245 RemapAndroidFiles(symfiles, os.path.abspath(options.output_directory)) | 1262 RemapAndroidFiles(symfiles, os.path.abspath(options.output_directory)) |
1246 | 1263 |
1247 | 1264 |
1248 if not trace.is_chromium: | 1265 if not trace.is_chromium: |
| 1266 # A non-chromium trace probably is not coming from the current machine. |
| 1267 # Don't attempt to symbolize system symbols, as that will produce the wrong |
| 1268 # results. |
| 1269 options.only_symbolize_chrome_symbols = True |
1249 if symbolizer.is_mac: | 1270 if symbolizer.is_mac: |
1250 RemapMacFiles(symfiles, options.symbol_base_directory, trace.version) | 1271 RemapMacFiles(symfiles, options.symbol_base_directory, trace.version, |
| 1272 options.only_symbolize_chrome_symbols) |
1251 if symbolizer.is_win: | 1273 if symbolizer.is_win: |
1252 RemapWinFiles(symfiles, options.symbol_base_directory, trace.version, | 1274 RemapWinFiles(symfiles, options.symbol_base_directory, trace.version, |
1253 trace.is_64bit) | 1275 trace.is_64bit, options.only_symbolize_chrome_symbols) |
1254 | 1276 |
1255 SymbolizeFiles(symfiles, symbolizer) | 1277 SymbolizeFiles(symfiles, symbolizer) |
1256 | 1278 |
1257 | 1279 |
1258 def OpenTraceFile(file_path, mode): | 1280 def OpenTraceFile(file_path, mode): |
1259 if file_path.endswith('.gz'): | 1281 if file_path.endswith('.gz'): |
1260 return gzip.open(file_path, mode + 'b') | 1282 return gzip.open(file_path, mode + 'b') |
1261 else: | 1283 else: |
1262 return open(file_path, mode + 't') | 1284 return open(file_path, mode + 't') |
1263 | 1285 |
1264 | 1286 |
1265 def FetchAndExtractSymbolsMac(symbol_base_directory, version): | 1287 def FetchAndExtractSymbolsMac(symbol_base_directory, version, |
| 1288 cloud_storage_bucket): |
1266 def GetLocalPath(base_dir, version): | 1289 def GetLocalPath(base_dir, version): |
1267 return os.path.join(base_dir, version + ".tar.bz2") | 1290 return os.path.join(base_dir, version + ".tar.bz2") |
1268 def GetSymbolsPath(version): | 1291 def GetSymbolsPath(version): |
1269 return "desktop-*/" + version + "/mac64/Google Chrome.dSYM.tar.bz2" | 1292 return "desktop-*/" + version + "/mac64/Google Chrome.dSYM.tar.bz2" |
1270 def ExtractSymbolTarFile(symbol_sub_dir, symbol_tar_file): | 1293 def ExtractSymbolTarFile(symbol_sub_dir, symbol_tar_file): |
1271 os.makedirs(symbol_sub_dir) | 1294 os.makedirs(symbol_sub_dir) |
1272 with tarfile.open(os.path.expanduser(symbol_tar_file), "r:bz2") as tar: | 1295 with tarfile.open(os.path.expanduser(symbol_tar_file), "r:bz2") as tar: |
1273 tar.extractall(symbol_sub_dir) | 1296 tar.extractall(symbol_sub_dir) |
1274 | 1297 |
1275 symbol_sub_dir = os.path.join(symbol_base_directory, version) | 1298 symbol_sub_dir = os.path.join(symbol_base_directory, version) |
1276 if os.path.isdir(symbol_sub_dir): | 1299 if os.path.isdir(symbol_sub_dir): |
1277 return True | 1300 return True |
1278 | 1301 |
1279 bzip_path = GetLocalPath(symbol_base_directory, version) | 1302 bzip_path = GetLocalPath(symbol_base_directory, version) |
1280 if not os.path.isfile(bzip_path): | 1303 if not os.path.isfile(bzip_path): |
1281 | 1304 |
1282 cloud_storage_bucket = "chrome-unsigned" | |
1283 if not cloud_storage.Exists(cloud_storage_bucket, GetSymbolsPath(version)): | 1305 if not cloud_storage.Exists(cloud_storage_bucket, GetSymbolsPath(version)): |
1284 print "Can't find symbols on GCS." | 1306 print "Can't find symbols on GCS." |
1285 return False | 1307 return False |
1286 print "Downloading symbols files from GCS, please wait." | 1308 print "Downloading symbols files from GCS, please wait." |
1287 cloud_storage.Get(cloud_storage_bucket, GetSymbolsPath(version), bzip_path) | 1309 cloud_storage.Get(cloud_storage_bucket, GetSymbolsPath(version), bzip_path) |
1288 | 1310 |
1289 ExtractSymbolTarFile(symbol_sub_dir, bzip_path) | 1311 ExtractSymbolTarFile(symbol_sub_dir, bzip_path) |
1290 return True | 1312 return True |
1291 | 1313 |
1292 | 1314 |
1293 def FetchAndExtractSymbolsWin(symbol_base_directory, version, is64bit): | 1315 def FetchAndExtractSymbolsWin(symbol_base_directory, version, is64bit, |
| 1316 cloud_storage_bucket): |
1294 def DownloadAndExtractZipFile(zip_path, source, destination): | 1317 def DownloadAndExtractZipFile(zip_path, source, destination): |
1295 if not os.path.isfile(zip_path): | 1318 if not os.path.isfile(zip_path): |
1296 cloud_storage_bucket = "chrome-unsigned" | |
1297 if not cloud_storage.Exists(cloud_storage_bucket, source): | 1319 if not cloud_storage.Exists(cloud_storage_bucket, source): |
1298 print "Can't find symbols on GCS." | 1320 print "Can't find symbols on GCS." |
1299 return False | 1321 return False |
1300 print "Downloading symbols files from GCS, please wait." | 1322 print "Downloading symbols files from GCS, please wait." |
1301 cloud_storage.Get(cloud_storage_bucket, source, zip_path) | 1323 cloud_storage.Get(cloud_storage_bucket, source, zip_path) |
1302 if not os.path.isfile(zip_path): | 1324 if not os.path.isfile(zip_path): |
1303 print "Can't download symbols on GCS." | 1325 print "Can't download symbols on GCS." |
1304 return False | 1326 return False |
1305 with zipfile.ZipFile(zip_path, "r") as zip_file: | 1327 with zipfile.ZipFile(zip_path, "r") as zip_file: |
1306 for member in zip_file.namelist(): | 1328 for member in zip_file.namelist(): |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1346 help='Trace file to symbolize (.json or .json.gz)') | 1368 help='Trace file to symbolize (.json or .json.gz)') |
1347 | 1369 |
1348 parser.add_argument( | 1370 parser.add_argument( |
1349 '--no-backup', dest='backup', default='true', action='store_false', | 1371 '--no-backup', dest='backup', default='true', action='store_false', |
1350 help="Don't create {} files".format(BACKUP_FILE_TAG)) | 1372 help="Don't create {} files".format(BACKUP_FILE_TAG)) |
1351 | 1373 |
1352 parser.add_argument( | 1374 parser.add_argument( |
1353 '--output-directory', | 1375 '--output-directory', |
1354 help='The path to the build output directory, such as out/Debug.') | 1376 help='The path to the build output directory, such as out/Debug.') |
1355 | 1377 |
| 1378 parser.add_argument( |
| 1379 '--only-symbolize-chrome-symbols', |
| 1380 action='store_true', |
| 1381 help='Prevents symbolization of non-Chrome [system] symbols.') |
| 1382 |
| 1383 parser.add_argument( |
| 1384 '--cloud-storage-bucket', default='chrome-unsigned', |
| 1385 help="Bucket that holds symbols for official Chrome builds. " |
| 1386 "Used by tests, which don't have access to the default bucket.") |
| 1387 |
1356 home_dir = os.path.expanduser('~') | 1388 home_dir = os.path.expanduser('~') |
1357 default_dir = os.path.join(home_dir, "symbols") | 1389 default_dir = os.path.join(home_dir, "symbols") |
1358 parser.add_argument( | 1390 parser.add_argument( |
1359 '--symbol-base-directory', | 1391 '--symbol-base-directory', |
1360 default=default_dir, | 1392 default=default_dir, |
1361 help='Directory where symbols are downloaded and cached.') | 1393 help='Directory where symbols are downloaded and cached.') |
1362 | 1394 |
1363 symbolizer = Symbolizer() | 1395 symbolizer = Symbolizer() |
1364 if symbolizer.symbolizer_path is None: | 1396 if symbolizer.symbolizer_path is None: |
1365 sys.exit("Can't symbolize - no %s in PATH." % symbolizer.binary) | 1397 sys.exit("Can't symbolize - no %s in PATH." % symbolizer.binary) |
(...skipping 12 matching lines...) Expand all Loading... |
1378 return False | 1410 return False |
1379 | 1411 |
1380 # If the trace is from Chromium, assume that symbols are already present. | 1412 # If the trace is from Chromium, assume that symbols are already present. |
1381 # Otherwise the trace is from Google Chrome. Assume that this is not a local | 1413 # Otherwise the trace is from Google Chrome. Assume that this is not a local |
1382 # build of Google Chrome with symbols, and that we need to fetch symbols | 1414 # build of Google Chrome with symbols, and that we need to fetch symbols |
1383 # from gcs. | 1415 # from gcs. |
1384 if not trace.is_chromium: | 1416 if not trace.is_chromium: |
1385 has_symbols = False | 1417 has_symbols = False |
1386 if symbolizer.is_mac: | 1418 if symbolizer.is_mac: |
1387 has_symbols = FetchAndExtractSymbolsMac(options.symbol_base_directory, | 1419 has_symbols = FetchAndExtractSymbolsMac(options.symbol_base_directory, |
1388 trace.version) | 1420 trace.version, |
| 1421 options.cloud_storage_bucket) |
1389 if symbolizer.is_win: | 1422 if symbolizer.is_win: |
1390 has_symbols = FetchAndExtractSymbolsWin(options.symbol_base_directory, | 1423 has_symbols = FetchAndExtractSymbolsWin(options.symbol_base_directory, |
1391 trace.version, trace.is_64bit) | 1424 trace.version, trace.is_64bit, |
| 1425 options.cloud_storage_bucket) |
1392 if not has_symbols: | 1426 if not has_symbols: |
1393 print 'Cannot fetch symbols from GCS' | 1427 print 'Cannot fetch symbols from GCS' |
1394 return False | 1428 return False |
1395 | 1429 |
1396 Symbolize(options, trace, symbolizer) | 1430 SymbolizeTrace(options, trace, symbolizer) |
1397 | 1431 |
1398 if trace.modified: | 1432 if trace.modified: |
1399 trace.ApplyModifications() | 1433 trace.ApplyModifications() |
1400 | 1434 |
1401 if options.backup: | 1435 if options.backup: |
1402 backup_file_path = trace_file_path + BACKUP_FILE_TAG | 1436 backup_file_path = trace_file_path + BACKUP_FILE_TAG |
1403 print 'Backing up trace file to {}'.format(backup_file_path) | 1437 print 'Backing up trace file to {}'.format(backup_file_path) |
1404 os.rename(trace_file_path, backup_file_path) | 1438 os.rename(trace_file_path, backup_file_path) |
1405 | 1439 |
1406 print 'Updating the trace file...' | 1440 print 'Updating the trace file...' |
1407 with OpenTraceFile(trace_file_path, 'w') as trace_file: | 1441 with OpenTraceFile(trace_file_path, 'w') as trace_file: |
1408 json.dump(trace.node, trace_file) | 1442 json.dump(trace.node, trace_file) |
1409 else: | 1443 else: |
1410 print 'No modifications were made - not updating the trace file.' | 1444 print 'No modifications were made - not updating the trace file.' |
| 1445 return True |
1411 | 1446 |
1412 | 1447 |
1413 if __name__ == '__main__': | 1448 if __name__ == '__main__': |
1414 main(sys.argv[1:]) | 1449 main(sys.argv[1:]) |
OLD | NEW |