1#!/usr/bin/env vpython3 2# 3# Copyright 2016 The Chromium Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7 8import argparse 9import os 10import re 11import sys 12import tempfile 13 14if __name__ == '__main__': 15 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 16from pylib.constants import host_paths 17 18if host_paths.DEVIL_PATH not in sys.path: 19 sys.path.append(host_paths.DEVIL_PATH) 20from devil.utils import cmd_helper 21 22 23_MICRODUMP_BEGIN = re.compile( 24 '.*google-breakpad: -----BEGIN BREAKPAD MICRODUMP-----') 25_MICRODUMP_END = re.compile( 26 '.*google-breakpad: -----END BREAKPAD MICRODUMP-----') 27 28""" Example Microdump 29<timestamp> 6270 6131 F google-breakpad: -----BEGIN BREAKPAD MICRODUMP----- 30<timestamp> 6270 6131 F google-breakpad: V Chrome_Android:54.0.2790.0 31... 32<timestamp> 6270 6131 F google-breakpad: -----END BREAKPAD MICRODUMP----- 33 34""" 35 36 37def GetMicroDumps(dump_path): 38 """Returns all microdumps found in given log file 39 40 Args: 41 dump_path: Path to the log file. 42 43 Returns: 44 List of all microdumps as lists of lines. 45 """ 46 with open(dump_path, 'r') as d: 47 data = d.read() 48 all_dumps = [] 49 current_dump = None 50 for line in data.splitlines(): 51 if current_dump is not None: 52 if _MICRODUMP_END.match(line): 53 current_dump.append(line) 54 all_dumps.append(current_dump) 55 current_dump = None 56 else: 57 current_dump.append(line) 58 elif _MICRODUMP_BEGIN.match(line): 59 current_dump = [] 60 current_dump.append(line) 61 return all_dumps 62 63 64def SymbolizeMicroDump(stackwalker_binary_path, dump, symbols_path): 65 """Runs stackwalker on microdump. 66 67 Runs the stackwalker binary at stackwalker_binary_path on a given microdump 68 using the symbols at symbols_path. 69 70 Args: 71 stackwalker_binary_path: Path to the stackwalker binary. 72 dump: The microdump to run the stackwalker on. 73 symbols_path: Path the the symbols file to use. 74 75 Returns: 76 Output from stackwalker tool. 77 """ 78 with tempfile.NamedTemporaryFile() as tf: 79 for l in dump: 80 tf.write('%s\n' % l) 81 cmd = [stackwalker_binary_path, tf.name, symbols_path] 82 return cmd_helper.GetCmdOutput(cmd) 83 84 85def AddArguments(parser): 86 parser.add_argument('--stackwalker-binary-path', required=True, 87 help='Path to stackwalker binary.') 88 parser.add_argument('--stack-trace-path', required=True, 89 help='Path to stacktrace containing microdump.') 90 parser.add_argument('--symbols-path', required=True, 91 help='Path to symbols file.') 92 parser.add_argument('--output-file', 93 help='Path to dump stacktrace output to') 94 95 96def _PrintAndLog(line, fp): 97 if fp: 98 fp.write('%s\n' % line) 99 print(line) 100 101 102def main(): 103 parser = argparse.ArgumentParser() 104 AddArguments(parser) 105 args = parser.parse_args() 106 107 micro_dumps = GetMicroDumps(args.stack_trace_path) 108 if not micro_dumps: 109 print('No microdump found. Exiting.') 110 return 0 111 112 symbolized_dumps = [] 113 for micro_dump in micro_dumps: 114 symbolized_dumps.append(SymbolizeMicroDump( 115 args.stackwalker_binary_path, micro_dump, args.symbols_path)) 116 117 try: 118 fp = open(args.output_file, 'w') if args.output_file else None 119 _PrintAndLog('%d microdumps found.' % len(micro_dumps), fp) 120 _PrintAndLog('---------- Start output from stackwalker ----------', fp) 121 for index, symbolized_dump in list(enumerate(symbolized_dumps)): 122 _PrintAndLog( 123 '------------------ Start dump %d ------------------' % index, fp) 124 _PrintAndLog(symbolized_dump, fp) 125 _PrintAndLog( 126 '------------------- End dump %d -------------------' % index, fp) 127 _PrintAndLog('----------- End output from stackwalker -----------', fp) 128 except Exception: 129 if fp: 130 fp.close() 131 raise 132 return 0 133 134 135if __name__ == '__main__': 136 sys.exit(main()) 137