blob: d1cc7216987ed8d6cfe7fb1c98bba9aede18c6d4 [file] [log] [blame]
Avi Drissman73a09d12022-09-08 20:33:381# Copyright 2017 The Chromium Authors
hzl55fc2af2017-07-27 08:24:502# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import os
7import re
hzl55fc2af2017-07-27 08:24:508import tempfile
Benjamin Pasteneb90971302017-12-20 02:41:209import time
hzl55fc2af2017-07-27 08:24:5010
11from devil.utils import cmd_helper
12from pylib import constants
Pâris503d25b2023-04-17 09:05:2313from pylib.constants import host_paths
14from .expensive_line_transformer import ExpensiveLineTransformer
15from .expensive_line_transformer import ExpensiveLineTransformerPool
hzl55fc2af2017-07-27 08:24:5016
Pâris503d25b2023-04-17 09:05:2317_STACK_TOOL = os.path.join(host_paths.ANDROID_PLATFORM_DEVELOPMENT_SCRIPTS_PATH,
18 'stack')
19_MINIMUM_TIMEOUT = 10.0
20_PER_LINE_TIMEOUT = .005 # Should be able to process 200 lines per second.
21_PROCESS_START_TIMEOUT = 20.0
22_MAX_RESTARTS = 4 # Should be plenty unless tool is crashing on start-up.
23_POOL_SIZE = 1
hzl55fc2af2017-07-27 08:24:5024ABI_REG = re.compile('ABI: \'(.+?)\'')
25
26
27def _DeviceAbiToArch(device_abi):
John Budorick906a32fc2019-06-26 16:00:2928 # The order of this list is significant to find the more specific match
29 # (e.g., arm64) before the less specific (e.g., arm).
30 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips']
31 for arch in arches:
32 if arch in device_abi:
33 return arch
34 raise RuntimeError('Unknown device ABI: %s' % device_abi)
hzl55fc2af2017-07-27 08:24:5035
36
Yoshisato Yanagisawa9f477792021-12-09 00:00:2537class Symbolizer:
hzl55fc2af2017-07-27 08:24:5038 """A helper class to symbolize stack."""
39
Andrew Grieve7c179d72018-07-11 03:05:0340 def __init__(self, apk_under_test=None):
hzl55fc2af2017-07-27 08:24:5041 self._apk_under_test = apk_under_test
Benjamin Pasteneb90971302017-12-20 02:41:2042 self._time_spent_symbolizing = 0
hzl55fc2af2017-07-27 08:24:5043
44
45 def __del__(self):
hzl55fc2af2017-07-27 08:24:5046 self.CleanUp()
47
48
49 def CleanUp(self):
50 """Clean up the temporary directory of apk libs."""
Benjamin Pasteneb90971302017-12-20 02:41:2051 if self._time_spent_symbolizing > 0:
52 logging.info(
53 'Total time spent symbolizing: %.2fs', self._time_spent_symbolizing)
hzl55fc2af2017-07-27 08:24:5054
55
hzl55fc2af2017-07-27 08:24:5056 def ExtractAndResolveNativeStackTraces(self, data_to_symbolize,
57 device_abi, include_stack=True):
58 """Run the stack tool for given input.
59
60 Args:
61 data_to_symbolize: a list of strings to symbolize.
62 include_stack: boolean whether to include stack data in output.
63 device_abi: the default ABI of the device which generated the tombstone.
64
65 Yields:
66 A string for each line of resolved stack output.
67 """
John Budorick906a32fc2019-06-26 16:00:2968 if not os.path.exists(_STACK_TOOL):
69 logging.warning('%s missing. Unable to resolve native stack traces.',
70 _STACK_TOOL)
71 return
72
hzl55fc2af2017-07-27 08:24:5073 arch = _DeviceAbiToArch(device_abi)
74 if not arch:
75 logging.warning('No device_abi can be found.')
76 return
77
78 cmd = [_STACK_TOOL, '--arch', arch, '--output-directory',
79 constants.GetOutDirectory(), '--more-info']
John Budorick8ddab762017-10-09 16:03:3680 env = dict(os.environ)
81 env['PYTHONDONTWRITEBYTECODE'] = '1'
Egor Paskoa61169b62021-07-05 14:16:1582 with tempfile.NamedTemporaryFile(mode='w') as f:
hzl55fc2af2017-07-27 08:24:5083 f.write('\n'.join(data_to_symbolize))
84 f.flush()
Benjamin Pasteneb90971302017-12-20 02:41:2085 start = time.time()
86 try:
87 _, output = cmd_helper.GetCmdStatusAndOutput(cmd + [f.name], env=env)
88 finally:
89 self._time_spent_symbolizing += time.time() - start
hzl55fc2af2017-07-27 08:24:5090 for line in output.splitlines():
91 if not include_stack and 'Stack Data:' in line:
92 break
93 yield line
Pâris503d25b2023-04-17 09:05:2394
95
96class PassThroughSymbolizer(ExpensiveLineTransformer):
97 def __init__(self, device_abi):
98 self._command = None
99 super().__init__(_PROCESS_START_TIMEOUT, _MINIMUM_TIMEOUT,
100 _PER_LINE_TIMEOUT)
101 if not os.path.exists(_STACK_TOOL):
102 logging.warning('%s: %s missing. Unable to resolve native stack traces.',
103 PassThroughSymbolizer.name, _STACK_TOOL)
104 return
105 arch = _DeviceAbiToArch(device_abi)
106 if not arch:
107 logging.warning('%s: No device_abi can be found.',
108 PassThroughSymbolizer.name)
109 return
110 self._command = [
111 _STACK_TOOL, '--arch', arch, '--output-directory',
112 constants.GetOutDirectory(), '--more-info', '--pass-through', '--flush',
113 '--quiet', '-'
114 ]
115 self.start()
116
117 @property
118 def name(self):
119 return "symbolizer"
120
121 @property
122 def command(self):
123 return self._command
124
125
126class PassThroughSymbolizerPool(ExpensiveLineTransformerPool):
127 def __init__(self, device_abi):
128 self._device_abi = device_abi
129 super().__init__(_MAX_RESTARTS, _POOL_SIZE)
130
131 def CreateTransformer(self):
132 return PassThroughSymbolizer(self._device_abi)
133
134 @property
135 def name(self):
136 return "symbolizer-pool"