Index: telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py |
diff --git a/telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py b/telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py |
index 3b2283e64d279cc3c2f0beb1cd0506403d360f22..c7fc67a20a4d268229726c8fa0a2f66442adf6ac 100644 |
--- a/telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py |
+++ b/telemetry/telemetry/internal/backends/chrome/desktop_browser_backend.py |
@@ -114,6 +114,7 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
self._proc = None |
self._tmp_profile_dir = None |
self._tmp_output_file = None |
+ self._most_recent_symbolized_minidump_paths = set([]) |
self._executable = executable |
if not self._executable: |
@@ -133,7 +134,7 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
self._browser_directory = browser_directory |
self._port = None |
self._tmp_minidump_dir = tempfile.mkdtemp() |
- if self.browser_options.enable_logging: |
+ if self.is_logging_enabled: |
self._log_file_path = os.path.join(tempfile.mkdtemp(), 'chrome.log') |
else: |
self._log_file_path = None |
@@ -141,6 +142,12 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
self._SetupProfile() |
@property |
+ def is_logging_enabled(self): |
+ return self.browser_options.logging_verbosity in [ |
+ self.browser_options.NON_VERBOSE_LOGGING, |
+ self.browser_options.VERBOSE_LOGGING] |
+ |
+ @property |
def log_file_path(self): |
return self._log_file_path |
@@ -268,7 +275,7 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
env = os.environ.copy() |
env['CHROME_HEADLESS'] = '1' # Don't upload minidumps. |
env['BREAKPAD_DUMP_LOCATION'] = self._tmp_minidump_dir |
- if self.browser_options.enable_logging: |
+ if self.is_logging_enabled: |
sys.stderr.write( |
'Chrome log file will be saved in %s\n' % self.log_file_path) |
env['CHROME_LOG_FILE'] = self.log_file_path |
@@ -326,7 +333,7 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
except IOError: |
return '' |
- def _GetMostRecentCrashpadMinidump(self): |
+ def _GetAllCrashpadMinidumps(self): |
os_name = self.browser.platform.GetOSName() |
arch_name = self.browser.platform.GetArchName() |
try: |
@@ -385,12 +392,19 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
logging.warning('Crashpad report expected valid keys' |
' "Path" and "Creation time": %s', e) |
+ return reports_list |
+ |
+ def _GetMostRecentCrashpadMinidump(self): |
+ reports_list = self._GetAllCrashpadMinidumps() |
if reports_list: |
_, most_recent_report_path = max(reports_list) |
return most_recent_report_path |
return None |
+ def _GetBreakPadMinidumpPaths(self): |
+ return glob.glob(os.path.join(self._tmp_minidump_dir, '*.dmp')) |
+ |
def _GetMostRecentMinidump(self): |
# Crashpad dump layout will be the standard eventually, check it first. |
most_recent_dump = self._GetMostRecentCrashpadMinidump() |
@@ -398,7 +412,7 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
# Typical breakpad format is simply dump files in a folder. |
if not most_recent_dump: |
logging.info('No minidump found via crashpad_database_util') |
- dumps = glob.glob(os.path.join(self._tmp_minidump_dir, '*.dmp')) |
+ dumps = self._GetBreakPadMinidumpPaths() |
if dumps: |
most_recent_dump = heapq.nlargest(1, dumps, os.path.getmtime)[0] |
if most_recent_dump: |
@@ -435,8 +449,16 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
if not cdb: |
logging.warning('cdb.exe not found.') |
return None |
+ # Include all the threads' stacks ("~*kb30") in addition to the |
+ # ostensibly crashed stack associated with the exception context |
+ # record (".ecxr;kb30"). Note that stack dumps, including that |
+ # for the crashed thread, may not be as precise as the one |
+ # starting from the exception context record. |
+ # Specify kb instead of k in order to get four arguments listed, for |
+ # easier diagnosis from stacks. |
output = subprocess.check_output([cdb, '-y', self._browser_directory, |
- '-c', '.ecxr;k30;q', '-z', minidump]) |
+ '-c', '.ecxr;kb30;~*kb30;q', |
+ '-z', minidump]) |
# cdb output can start the stack with "ChildEBP", "Child-SP", and possibly |
# other things we haven't seen yet. If we can't find the start of the |
# stack, include output from the beginning. |
@@ -490,13 +512,42 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): |
if not most_recent_dump: |
return (False, 'No crash dump found.') |
logging.info('Minidump found: %s' % most_recent_dump) |
- stack = self._GetStackFromMinidump(most_recent_dump) |
+ return self._InternalSymbolizeMinidump(most_recent_dump) |
+ |
+ def GetMostRecentMinidumpPath(self): |
+ return self._GetMostRecentMinidump() |
+ |
+ def GetAllMinidumpPaths(self): |
+ reports_list = self._GetAllCrashpadMinidumps() |
+ if reports_list: |
+ return [report[1] for report in reports_list] |
+ else: |
+ logging.info('No minidump found via crashpad_database_util') |
+ dumps = self._GetBreakPadMinidumpPaths() |
+ if dumps: |
+ logging.info('Found minidump via globbing in minidump dir') |
+ return dumps |
+ return None |
+ |
+ def GetAllUnsymbolizedMinidumpPaths(self): |
+ minidump_paths = set(self.GetAllMinidumpPaths()) |
+ # If we have already symbolized paths remove them from the list |
+ unsymbolized_paths = (minidump_paths |
+ - self._most_recent_symbolized_minidump_paths) |
+ return list(unsymbolized_paths) |
+ |
+ def SymbolizeMinidump(self, minidump_path): |
+ return self._InternalSymbolizeMinidump(minidump_path) |
+ |
+ def _InternalSymbolizeMinidump(self, minidump_path): |
+ stack = self._GetStackFromMinidump(minidump_path) |
if not stack: |
- cloud_storage_link = self._UploadMinidumpToCloudStorage(most_recent_dump) |
+ cloud_storage_link = self._UploadMinidumpToCloudStorage(minidump_path) |
error_message = ('Failed to symbolize minidump. Raw stack is uploaded to' |
' cloud storage: %s.' % cloud_storage_link) |
return (False, error_message) |
+ self._most_recent_symbolized_minidump_paths.add(minidump_path) |
return (True, stack) |
def __del__(self): |