xref: /aosp_15_r20/external/angle/build/android/stacktrace/stackwalker.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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