stackwalker.py 3.9 KB

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