| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 # | 6 # |
| 7 # Find the most recent tombstone file(s) on all connected devices | 7 # Find the most recent tombstone file(s) on all connected devices |
| 8 # and prints their stacks. | 8 # and prints their stacks. |
| 9 # | 9 # |
| 10 # Assumes tombstone file was created with current symbols. | 10 # Assumes tombstone file was created with current symbols. |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 def _DeviceAbiToArch(device_abi): | 99 def _DeviceAbiToArch(device_abi): |
| 100 # The order of this list is significant to find the more specific match (e.g., | 100 # The order of this list is significant to find the more specific match (e.g., |
| 101 # arm64) before the less specific (e.g., arm). | 101 # arm64) before the less specific (e.g., arm). |
| 102 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips'] | 102 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips'] |
| 103 for arch in arches: | 103 for arch in arches: |
| 104 if arch in device_abi: | 104 if arch in device_abi: |
| 105 return arch | 105 return arch |
| 106 raise RuntimeError('Unknown device ABI: %s' % device_abi) | 106 raise RuntimeError('Unknown device ABI: %s' % device_abi) |
| 107 | 107 |
| 108 | 108 |
| 109 def _ResolveSymbols(tombstone_data, include_stack, device_abi): | 109 def _ResolveSymbols(tombstone_data, include_stack, device_abi, packed_libs): |
| 110 """Run the stack tool for given tombstone input. | 110 """Run the stack tool for given tombstone input. |
| 111 | 111 |
| 112 Args: | 112 Args: |
| 113 tombstone_data: a list of strings of tombstone data. | 113 tombstone_data: a list of strings of tombstone data. |
| 114 include_stack: boolean whether to include stack data in output. | 114 include_stack: boolean whether to include stack data in output. |
| 115 device_abi: the default ABI of the device which generated the tombstone. | 115 device_abi: the default ABI of the device which generated the tombstone. |
| 116 | 116 |
| 117 Yields: | 117 Yields: |
| 118 A string for each line of resolved stack output. | 118 A string for each line of resolved stack output. |
| 119 """ | 119 """ |
| 120 # Check if the tombstone data has an ABI listed, if so use this in preference | 120 # Check if the tombstone data has an ABI listed, if so use this in preference |
| 121 # to the device's default ABI. | 121 # to the device's default ABI. |
| 122 for line in tombstone_data: | 122 for line in tombstone_data: |
| 123 found_abi = re.search('ABI: \'(.+?)\'', line) | 123 found_abi = re.search('ABI: \'(.+?)\'', line) |
| 124 if found_abi: | 124 if found_abi: |
| 125 device_abi = found_abi.group(1) | 125 device_abi = found_abi.group(1) |
| 126 arch = _DeviceAbiToArch(device_abi) | 126 arch = _DeviceAbiToArch(device_abi) |
| 127 if not arch: | 127 if not arch: |
| 128 return | 128 return |
| 129 | 129 |
| 130 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', | 130 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', |
| 131 'third_party', 'android_platform', 'development', | 131 'third_party', 'android_platform', 'development', |
| 132 'scripts', 'stack') | 132 'scripts', 'stack') |
| 133 cmd = [stack_tool, '--arch', arch, '--output-directory', | 133 cmd = [stack_tool, '--arch', arch, '--output-directory', |
| 134 constants.GetOutDirectory()] | 134 constants.GetOutDirectory()] |
| 135 if packed_libs: |
| 136 for packed_lib in packed_libs: |
| 137 cmd.extend(['--packed-lib', packed_lib]) |
| 135 proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | 138 proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
| 136 output = proc.communicate(input='\n'.join(tombstone_data))[0] | 139 output = proc.communicate(input='\n'.join(tombstone_data))[0] |
| 137 for line in output.split('\n'): | 140 for line in output.split('\n'): |
| 138 if not include_stack and 'Stack Data:' in line: | 141 if not include_stack and 'Stack Data:' in line: |
| 139 break | 142 break |
| 140 yield line | 143 yield line |
| 141 | 144 |
| 142 | 145 |
| 143 def _ResolveTombstone(tombstone): | 146 def _ResolveTombstone(args): |
| 147 tombstone = args[0] |
| 148 packed_libs = args[1] |
| 144 lines = [] | 149 lines = [] |
| 145 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + | 150 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + |
| 146 ', about this long ago: ' + | 151 ', about this long ago: ' + |
| 147 (str(tombstone['device_now'] - tombstone['time']) + | 152 (str(tombstone['device_now'] - tombstone['time']) + |
| 148 ' Device: ' + tombstone['serial'])] | 153 ' Device: ' + tombstone['serial'])] |
| 149 logging.info('\n'.join(lines)) | 154 logging.info('\n'.join(lines)) |
| 150 logging.info('Resolving...') | 155 logging.info('Resolving...') |
| 151 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], | 156 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], |
| 152 tombstone['device_abi']) | 157 tombstone['device_abi'], |
| 158 packed_libs) |
| 153 return lines | 159 return lines |
| 154 | 160 |
| 155 | 161 |
| 156 def _ResolveTombstones(jobs, tombstones): | 162 def _ResolveTombstones(jobs, tombstones, packed_libs): |
| 157 """Resolve a list of tombstones. | 163 """Resolve a list of tombstones. |
| 158 | 164 |
| 159 Args: | 165 Args: |
| 160 jobs: the number of jobs to use with multiprocess. | 166 jobs: the number of jobs to use with multiprocess. |
| 161 tombstones: a list of tombstones. | 167 tombstones: a list of tombstones. |
| 162 """ | 168 """ |
| 163 if not tombstones: | 169 if not tombstones: |
| 164 logging.warning('No tombstones to resolve.') | 170 logging.warning('No tombstones to resolve.') |
| 165 return [] | 171 return [] |
| 166 if len(tombstones) == 1: | 172 if len(tombstones) == 1: |
| 167 data = [_ResolveTombstone(tombstones[0])] | 173 data = [_ResolveTombstone([tombstones[0], packed_libs])] |
| 168 else: | 174 else: |
| 169 pool = multiprocessing.Pool(processes=jobs) | 175 pool = multiprocessing.Pool(processes=jobs) |
| 170 data = pool.map(_ResolveTombstone, tombstones) | 176 data = pool.map(_ResolveTombstone, |
| 177 [[tombstone, packed_libs] for tombstone in tombstones]) |
| 171 resolved_tombstones = [] | 178 resolved_tombstones = [] |
| 172 for tombstone in data: | 179 for tombstone in data: |
| 173 resolved_tombstones.extend(tombstone) | 180 resolved_tombstones.extend(tombstone) |
| 174 return resolved_tombstones | 181 return resolved_tombstones |
| 175 | 182 |
| 176 | 183 |
| 177 def _GetTombstonesForDevice(device, resolve_all_tombstones, | 184 def _GetTombstonesForDevice(device, resolve_all_tombstones, |
| 178 include_stack_symbols, | 185 include_stack_symbols, |
| 179 wipe_tombstones): | 186 wipe_tombstones): |
| 180 """Returns a list of tombstones on a given device. | 187 """Returns a list of tombstones on a given device. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 """ | 236 """ |
| 230 all_tombstones = list(_ListTombstones(device)) | 237 all_tombstones = list(_ListTombstones(device)) |
| 231 if not all_tombstones: | 238 if not all_tombstones: |
| 232 logging.warning('No tombstones to clear.') | 239 logging.warning('No tombstones to clear.') |
| 233 | 240 |
| 234 for tombstone_file, _ in all_tombstones: | 241 for tombstone_file, _ in all_tombstones: |
| 235 _EraseTombstone(device, tombstone_file) | 242 _EraseTombstone(device, tombstone_file) |
| 236 | 243 |
| 237 | 244 |
| 238 def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols, | 245 def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols, |
| 239 wipe_tombstones, jobs=4): | 246 wipe_tombstones, jobs=4, packed_libs=None): |
| 240 """Resolve tombstones in the device. | 247 """Resolve tombstones in the device. |
| 241 | 248 |
| 242 Args: | 249 Args: |
| 243 device: An instance of DeviceUtils. | 250 device: An instance of DeviceUtils. |
| 244 resolve_all_tombstone: Whether to resolve every tombstone. | 251 resolve_all_tombstone: Whether to resolve every tombstone. |
| 245 include_stack_symbols: Whether to include symbols for stack data. | 252 include_stack_symbols: Whether to include symbols for stack data. |
| 246 wipe_tombstones: Whether to wipe tombstones. | 253 wipe_tombstones: Whether to wipe tombstones. |
| 247 jobs: Number of jobs to use when processing multiple crash stacks. | 254 jobs: Number of jobs to use when processing multiple crash stacks. |
| 248 | 255 |
| 249 Returns: | 256 Returns: |
| 250 A list of resolved tombstones. | 257 A list of resolved tombstones. |
| 251 """ | 258 """ |
| 252 return _ResolveTombstones(jobs, | 259 return _ResolveTombstones(jobs, |
| 253 _GetTombstonesForDevice(device, | 260 _GetTombstonesForDevice(device, |
| 254 resolve_all_tombstones, | 261 resolve_all_tombstones, |
| 255 include_stack_symbols, | 262 include_stack_symbols, |
| 256 wipe_tombstones)) | 263 wipe_tombstones), |
| 264 packed_libs) |
| 257 | 265 |
| 258 | 266 |
| 259 def main(): | 267 def main(): |
| 260 custom_handler = logging.StreamHandler(sys.stdout) | 268 custom_handler = logging.StreamHandler(sys.stdout) |
| 261 custom_handler.setFormatter(run_tests_helper.CustomFormatter()) | 269 custom_handler.setFormatter(run_tests_helper.CustomFormatter()) |
| 262 logging.getLogger().addHandler(custom_handler) | 270 logging.getLogger().addHandler(custom_handler) |
| 263 logging.getLogger().setLevel(logging.INFO) | 271 logging.getLogger().setLevel(logging.INFO) |
| 264 | 272 |
| 265 parser = argparse.ArgumentParser() | 273 parser = argparse.ArgumentParser() |
| 266 parser.add_argument('--device', | 274 parser.add_argument('--device', |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 for device in devices: | 314 for device in devices: |
| 307 resolved_tombstones = ResolveTombstones( | 315 resolved_tombstones = ResolveTombstones( |
| 308 device, args.all_tombstones, | 316 device, args.all_tombstones, |
| 309 args.stack, args.wipe_tombstones, args.jobs) | 317 args.stack, args.wipe_tombstones, args.jobs) |
| 310 for line in resolved_tombstones: | 318 for line in resolved_tombstones: |
| 311 logging.info(line) | 319 logging.info(line) |
| 312 | 320 |
| 313 | 321 |
| 314 if __name__ == '__main__': | 322 if __name__ == '__main__': |
| 315 sys.exit(main()) | 323 sys.exit(main()) |
| OLD | NEW |