17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#!/usr/bin/env python 27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# 37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Copyright 2013 The Chromium Authors. All rights reserved. 47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Use of this source code is governed by a BSD-style license that can be 57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# found in the LICENSE file. 67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Find the most recent tombstone file(s) on all connected devices 87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# and prints their stacks. 97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# 107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Assumes tombstone file was created with current symbols. 117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport datetime 137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport logging 147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport multiprocessing 157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport os 167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport subprocess 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport sys 187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport optparse 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom pylib import android_commands 217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _ListTombstones(adb): 247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """List the tombstone files on the device. 257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch adb: An instance of AndroidCommands. 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Yields: 307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Tuples of (tombstone filename, date time of file on device). 317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch lines = adb.RunShellCommand('TZ=UTC su -c ls -a -l /data/tombstones') 337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for line in lines: 347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if 'tombstone' in line and not 'No such file or directory' in line: 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch details = line.split() 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch t = datetime.datetime.strptime(details[-3] + ' ' + details[-2], 377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch '%Y-%m-%d %H:%M') 387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch yield details[-1], t 397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _GetDeviceDateTime(adb): 427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Determine the date time on the device. 437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch adb: An instance of AndroidCommands. 467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Returns: 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch A datetime instance. 497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch device_now_string = adb.RunShellCommand('TZ=UTC date') 517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return datetime.datetime.strptime( 527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch device_now_string[0], '%a %b %d %H:%M:%S %Z %Y') 537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _GetTombstoneData(adb, tombstone_file): 567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Retrieve the tombstone data from the device 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstone_file: the tombstone to retrieve 607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Returns: 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch A list of lines 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return adb.GetProtectedFileContents('/data/tombstones/' + tombstone_file) 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _EraseTombstone(adb, tombstone_file): 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Deletes a tombstone from the device. 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstone_file: the tombstone to delete. 727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return adb.RunShellCommand('su -c rm /data/tombstones/' + tombstone_file) 747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _ResolveSymbols(tombstone_data, include_stack): 777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Run the stack tool for given tombstone input. 787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstone_data: a list of strings of tombstone data. 817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch include_stack: boolean whether to include stack data in output. 827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Yields: 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch A string for each line of resolved stack output. 857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', 877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'third_party', 'android_platform', 'development', 887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'scripts', 'stack') 897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch proc = subprocess.Popen(stack_tool, stdin=subprocess.PIPE, 907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch stdout=subprocess.PIPE) 917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch output = proc.communicate(input='\n'.join(tombstone_data))[0] 927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for line in output.split('\n'): 937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not include_stack and 'Stack Data:' in line: 947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch break 957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch yield line 967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _ResolveTombstone(tombstone): 997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch lines = [] 1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + 1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ', about this long ago: ' + 1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch (str(tombstone['device_now'] - tombstone['time']) + 1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ' Device: ' + tombstone['serial'])] 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch print '\n'.join(lines) 1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch print 'Resolving...' 1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch lines += _ResolveSymbols(tombstone['data'], tombstone['stack']) 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return lines 1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _ResolveTombstones(jobs, tombstones): 1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Resolve a list of tombstones. 1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch jobs: the number of jobs to use with multiprocess. 1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstones: a list of tombstones. 1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not tombstones: 1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch print 'No device attached? Or no tombstones?' 1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return 1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if len(tombstones) == 1: 1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch data = _ResolveTombstone(tombstones[0]) 1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pool = multiprocessing.Pool(processes=jobs) 1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch data = pool.map(_ResolveTombstone, tombstones) 1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch data = ['\n'.join(d) for d in data] 1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch print '\n'.join(data) 1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef _GetTombstonesForDevice(adb, options): 1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """Returns a list of tombstones on a given adb connection. 1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch Args: 1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch adb: An instance of Androidcommands. 1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch options: command line arguments from OptParse 1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch """ 1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ret = [] 1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch all_tombstones = list(_ListTombstones(adb)) 1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if not all_tombstones: 1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch print 'No device attached? Or no tombstones?' 1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return ret 1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch # Sort the tombstones in date order, descending 1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) 1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch # Only resolve the most recent unless --all-tombstones given. 1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] 1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch device_now = _GetDeviceDateTime(adb) 1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for tombstone_file, tombstone_time in tombstones: 1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ret += [{'serial': adb.Adb().GetSerialNumber(), 1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'device_now': device_now, 1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'time': tombstone_time, 1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'file': tombstone_file, 1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'stack': options.stack, 1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'data': _GetTombstoneData(adb, tombstone_file)}] 1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch # Erase all the tombstones if desired. 1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if options.wipe_tombstones: 1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for tombstone_file, _ in all_tombstones: 1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch _EraseTombstone(adb, tombstone_file) 1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return ret 1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochdef main(): 1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser = optparse.OptionParser() 1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser.add_option('--device', 1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch help='The serial number of the device. If not specified ' 1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'will use all devices.') 1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser.add_option('-a', '--all-tombstones', action='store_true', 1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch help="""Resolve symbols for all tombstones, rather than just 1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch the most recent""") 1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser.add_option('-s', '--stack', action='store_true', 1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch help='Also include symbols for stack data') 1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser.add_option('-w', '--wipe-tombstones', action='store_true', 1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch help='Erase all tombstones from device after processing') 1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch parser.add_option('-j', '--jobs', type='int', 1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch default=4, 1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch help='Number of jobs to use when processing multiple ' 1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'crash stacks.') 1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch options, args = parser.parse_args() 1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if options.device: 1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch devices = [options.device] 1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch else: 1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch devices = android_commands.GetAttachedDevices() 1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstones = [] 1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch for device in devices: 1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch adb = android_commands.AndroidCommands(device) 1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch tombstones += _GetTombstonesForDevice(adb, options) 1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch _ResolveTombstones(options.jobs, tombstones) 1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochif __name__ == '__main__': 1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch sys.exit(main()) 196