blob: ad60e998281da1d31d5294ff40284a2eed202f23 [file] [log] [blame] [edit]
#!/usr/bin/env vpython3
#
# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import os
import re
import sys
import tempfile
if __name__ == '__main__':
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from pylib.constants import host_paths
if host_paths.DEVIL_PATH not in sys.path:
sys.path.append(host_paths.DEVIL_PATH)
from devil.utils import cmd_helper
_MICRODUMP_BEGIN = re.compile(
'.*google-breakpad: -----BEGIN BREAKPAD MICRODUMP-----')
_MICRODUMP_END = re.compile(
'.*google-breakpad: -----END BREAKPAD MICRODUMP-----')
""" Example Microdump
<timestamp> 6270 6131 F google-breakpad: -----BEGIN BREAKPAD MICRODUMP-----
<timestamp> 6270 6131 F google-breakpad: V Chrome_Android:54.0.2790.0
...
<timestamp> 6270 6131 F google-breakpad: -----END BREAKPAD MICRODUMP-----
"""
def GetMicroDumps(dump_path):
"""Returns all microdumps found in given log file
Args:
dump_path: Path to the log file.
Returns:
List of all microdumps as lists of lines.
"""
with open(dump_path, 'r') as d:
data = d.read()
all_dumps = []
current_dump = None
for line in data.splitlines():
if current_dump is not None:
if _MICRODUMP_END.match(line):
current_dump.append(line)
all_dumps.append(current_dump)
current_dump = None
else:
current_dump.append(line)
elif _MICRODUMP_BEGIN.match(line):
current_dump = []
current_dump.append(line)
return all_dumps
def SymbolizeMicroDump(stackwalker_binary_path, dump, symbols_path):
"""Runs stackwalker on microdump.
Runs the stackwalker binary at stackwalker_binary_path on a given microdump
using the symbols at symbols_path.
Args:
stackwalker_binary_path: Path to the stackwalker binary.
dump: The microdump to run the stackwalker on.
symbols_path: Path the the symbols file to use.
Returns:
Output from stackwalker tool.
"""
with tempfile.NamedTemporaryFile() as tf:
for l in dump:
tf.write('%s\n' % l)
cmd = [stackwalker_binary_path, tf.name, symbols_path]
return cmd_helper.GetCmdOutput(cmd)
def AddArguments(parser):
parser.add_argument('--stackwalker-binary-path', required=True,
help='Path to stackwalker binary.')
parser.add_argument('--stack-trace-path', required=True,
help='Path to stacktrace containing microdump.')
parser.add_argument('--symbols-path', required=True,
help='Path to symbols file.')
parser.add_argument('--output-file',
help='Path to dump stacktrace output to')
def _PrintAndLog(line, fp):
if fp:
fp.write('%s\n' % line)
print(line)
def main():
parser = argparse.ArgumentParser()
AddArguments(parser)
args = parser.parse_args()
micro_dumps = GetMicroDumps(args.stack_trace_path)
if not micro_dumps:
print('No microdump found. Exiting.')
return 0
symbolized_dumps = []
for micro_dump in micro_dumps:
symbolized_dumps.append(SymbolizeMicroDump(
args.stackwalker_binary_path, micro_dump, args.symbols_path))
try:
fp = open(args.output_file, 'w') if args.output_file else None
_PrintAndLog('%d microdumps found.' % len(micro_dumps), fp)
_PrintAndLog('---------- Start output from stackwalker ----------', fp)
for index, symbolized_dump in list(enumerate(symbolized_dumps)):
_PrintAndLog(
'------------------ Start dump %d ------------------' % index, fp)
_PrintAndLog(symbolized_dump, fp)
_PrintAndLog(
'------------------- End dump %d -------------------' % index, fp)
_PrintAndLog('----------- End output from stackwalker -----------', fp)
except Exception:
if fp:
fp.close()
raise
return 0
if __name__ == '__main__':
sys.exit(main())