| OLD | NEW |
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 import logging | 30 import logging |
| 31 | 31 |
| 32 from webkitpy.common.webkit_finder import WebKitFinder | 32 from webkitpy.common.webkit_finder import WebKitFinder |
| 33 from webkitpy.layout_tests.breakpad.dump_reader import DumpReader | 33 from webkitpy.layout_tests.breakpad.dump_reader import DumpReader |
| 34 | 34 |
| 35 | 35 |
| 36 _log = logging.getLogger(__name__) | 36 _log = logging.getLogger(__name__) |
| 37 | 37 |
| 38 | 38 |
| 39 class DumpReaderMultipart(DumpReader): | 39 class DumpReaderMultipart(DumpReader): |
| 40 |
| 40 """Base class for Linux and Android breakpad dump reader.""" | 41 """Base class for Linux and Android breakpad dump reader.""" |
| 41 | 42 |
| 42 def __init__(self, host, build_dir): | 43 def __init__(self, host, build_dir): |
| 43 super(DumpReaderMultipart, self).__init__(host, build_dir) | 44 super(DumpReaderMultipart, self).__init__(host, build_dir) |
| 44 self._webkit_finder = WebKitFinder(host.filesystem) | 45 self._webkit_finder = WebKitFinder(host.filesystem) |
| 45 self._breakpad_tools_available = None | 46 self._breakpad_tools_available = None |
| 46 self._generated_symbols = False | 47 self._generated_symbols = False |
| 47 | 48 |
| 48 def check_is_functional(self): | 49 def check_is_functional(self): |
| 49 return self._check_breakpad_tools_available() | 50 return self._check_breakpad_tools_available() |
| 50 | 51 |
| 51 def _get_pid_from_dump(self, dump_file): | 52 def _get_pid_from_dump(self, dump_file): |
| 52 dump = self._read_dump(dump_file) | 53 dump = self._read_dump(dump_file) |
| 53 if not dump: | 54 if not dump: |
| 54 return None | 55 return None |
| 55 if 'pid' in dump: | 56 if 'pid' in dump: |
| 56 return dump['pid'][0] | 57 return dump['pid'][0] |
| 57 return None | 58 return None |
| 58 | 59 |
| 59 def _get_stack_from_dump(self, dump_file): | 60 def _get_stack_from_dump(self, dump_file): |
| 60 dump = self._read_dump(dump_file) | 61 dump = self._read_dump(dump_file) |
| 61 if not dump: | 62 if not dump: |
| 62 return None | 63 return None |
| 63 if not 'upload_file_minidump' in dump: | 64 if not 'upload_file_minidump' in dump: |
| 64 return None | 65 return None |
| 65 | 66 |
| 66 self._generate_breakpad_symbols_if_necessary() | 67 self._generate_breakpad_symbols_if_necessary() |
| 67 f, temp_name = self._host.filesystem.open_binary_tempfile('dmp') | 68 f, temp_name = self._host.filesystem.open_binary_tempfile('dmp') |
| 68 f.write("\r\n".join(dump['upload_file_minidump'])) | 69 f.write('\r\n'.join(dump['upload_file_minidump'])) |
| 69 f.close() | 70 f.close() |
| 70 | 71 |
| 71 cmd = [self._path_to_minidump_stackwalk(), temp_name, self._symbols_dir(
)] | 72 cmd = [self._path_to_minidump_stackwalk(), temp_name, self._symbols_dir(
)] |
| 72 try: | 73 try: |
| 73 stack = self._host.executive.run_command(cmd, return_stderr=False) | 74 stack = self._host.executive.run_command(cmd, return_stderr=False) |
| 74 except: | 75 except: |
| 75 _log.warning('Failed to execute "%s"' % ' '.join(cmd)) | 76 _log.warning('Failed to execute "%s"' % ' '.join(cmd)) |
| 76 stack = None | 77 stack = None |
| 77 finally: | 78 finally: |
| 78 self._host.filesystem.remove(temp_name) | 79 self._host.filesystem.remove(temp_name) |
| 79 return stack | 80 return stack |
| 80 | 81 |
| 81 def _read_dump(self, dump_file): | 82 def _read_dump(self, dump_file): |
| 82 with self._host.filesystem.open_binary_file_for_reading(dump_file) as f: | 83 with self._host.filesystem.open_binary_file_for_reading(dump_file) as f: |
| 83 boundary = f.readline().strip()[2:] | 84 boundary = f.readline().strip()[2:] |
| 84 f.seek(0) | 85 f.seek(0) |
| 85 try: | 86 try: |
| 86 data = cgi.parse_multipart(f, {'boundary': boundary}) | 87 data = cgi.parse_multipart(f, {'boundary': boundary}) |
| 87 return data | 88 return data |
| 88 except: | 89 except: |
| 89 pass | 90 pass |
| 90 return None | 91 return None |
| 91 | 92 |
| 92 def _check_breakpad_tools_available(self): | 93 def _check_breakpad_tools_available(self): |
| 93 if self._breakpad_tools_available != None: | 94 if self._breakpad_tools_available is not None: |
| 94 return self._breakpad_tools_available | 95 return self._breakpad_tools_available |
| 95 | 96 |
| 96 REQUIRED_BREAKPAD_TOOLS = [ | 97 REQUIRED_BREAKPAD_TOOLS = [ |
| 97 'dump_syms', | 98 'dump_syms', |
| 98 'minidump_stackwalk', | 99 'minidump_stackwalk', |
| 99 ] | 100 ] |
| 100 result = True | 101 result = True |
| 101 for binary in REQUIRED_BREAKPAD_TOOLS: | 102 for binary in REQUIRED_BREAKPAD_TOOLS: |
| 102 full_path = self._host.filesystem.join(self._build_dir, binary) | 103 full_path = self._host.filesystem.join(self._build_dir, binary) |
| 103 if not self._host.filesystem.exists(full_path): | 104 if not self._host.filesystem.exists(full_path): |
| 104 result = False | 105 result = False |
| 105 _log.error('Unable to find %s' % binary) | 106 _log.error('Unable to find %s' % binary) |
| 106 _log.error(' at %s' % full_path) | 107 _log.error(' at %s' % full_path) |
| 107 | 108 |
| 108 if not result: | 109 if not result: |
| 109 _log.error(" Could not find breakpad tools, unexpected crashes wo
n't be symbolized") | 110 _log.error(" Could not find breakpad tools, unexpected crashes wo
n't be symbolized") |
| 110 _log.error(' Did you build the target blink_tests?') | 111 _log.error(' Did you build the target blink_tests?') |
| 111 _log.error('') | 112 _log.error('') |
| 112 | 113 |
| 113 self._breakpad_tools_available = result | 114 self._breakpad_tools_available = result |
| 114 return self._breakpad_tools_available | 115 return self._breakpad_tools_available |
| 115 | 116 |
| 116 def _path_to_minidump_stackwalk(self): | 117 def _path_to_minidump_stackwalk(self): |
| 117 return self._host.filesystem.join(self._build_dir, "minidump_stackwalk") | 118 return self._host.filesystem.join(self._build_dir, 'minidump_stackwalk') |
| 118 | 119 |
| 119 def _path_to_generate_breakpad_symbols(self): | 120 def _path_to_generate_breakpad_symbols(self): |
| 120 return self._webkit_finder.path_from_chromium_base("components", "crash"
, "tools", "generate_breakpad_symbols.py") | 121 return self._webkit_finder.path_from_chromium_base('components', 'crash'
, 'tools', 'generate_breakpad_symbols.py') |
| 121 | 122 |
| 122 def _symbols_dir(self): | 123 def _symbols_dir(self): |
| 123 return self._host.filesystem.join(self._build_dir, 'content_shell.syms') | 124 return self._host.filesystem.join(self._build_dir, 'content_shell.syms') |
| 124 | 125 |
| 125 def _generate_breakpad_symbols_if_necessary(self): | 126 def _generate_breakpad_symbols_if_necessary(self): |
| 126 if self._generated_symbols: | 127 if self._generated_symbols: |
| 127 return | 128 return |
| 128 self._generated_symbols = True | 129 self._generated_symbols = True |
| 129 | 130 |
| 130 _log.debug("Generating breakpad symbols") | 131 _log.debug('Generating breakpad symbols') |
| 131 for binary in self._binaries_to_symbolize(): | 132 for binary in self._binaries_to_symbolize(): |
| 132 full_path = self._host.filesystem.join(self._build_dir, binary) | 133 full_path = self._host.filesystem.join(self._build_dir, binary) |
| 133 cmd = [ | 134 cmd = [ |
| 134 self._path_to_generate_breakpad_symbols(), | 135 self._path_to_generate_breakpad_symbols(), |
| 135 '--binary=%s' % full_path, | 136 '--binary=%s' % full_path, |
| 136 '--symbols-dir=%s' % self._symbols_dir(), | 137 '--symbols-dir=%s' % self._symbols_dir(), |
| 137 '--build-dir=%s' % self._build_dir, | 138 '--build-dir=%s' % self._build_dir, |
| 138 ] | 139 ] |
| 139 try: | 140 try: |
| 140 self._host.executive.run_command(cmd) | 141 self._host.executive.run_command(cmd) |
| 141 except: | 142 except: |
| 142 _log.error('Failed to execute "%s"' % ' '.join(cmd)) | 143 _log.error('Failed to execute "%s"' % ' '.join(cmd)) |
| 143 | 144 |
| 144 def _binaries_to_symbolize(self): | 145 def _binaries_to_symbolize(self): |
| 145 """This routine must be implemented by subclasses. | 146 """This routine must be implemented by subclasses. |
| 146 | 147 |
| 147 Returns an array of binaries that need to be symbolized.""" | 148 Returns an array of binaries that need to be symbolized.""" |
| 148 raise NotImplementedError() | 149 raise NotImplementedError() |
| 149 | 150 |
| 150 | 151 |
| 151 class DumpReaderLinux(DumpReaderMultipart): | 152 class DumpReaderLinux(DumpReaderMultipart): |
| 153 |
| 152 """Linux breakpad dump reader.""" | 154 """Linux breakpad dump reader.""" |
| 153 | 155 |
| 154 def _binaries_to_symbolize(self): | 156 def _binaries_to_symbolize(self): |
| 155 return ['content_shell', 'libtest_netscape_plugin.so', 'libffmpegsumo.so
', 'libosmesa.so'] | 157 return ['content_shell', 'libtest_netscape_plugin.so', 'libffmpegsumo.so
', 'libosmesa.so'] |
| 156 | 158 |
| 157 def _file_extension(self): | 159 def _file_extension(self): |
| 158 return 'dmp' | 160 return 'dmp' |
| 159 | 161 |
| 160 | 162 |
| 161 class DumpReaderAndroid(DumpReaderMultipart): | 163 class DumpReaderAndroid(DumpReaderMultipart): |
| 164 |
| 162 """Android breakpad dump reader.""" | 165 """Android breakpad dump reader.""" |
| 163 | 166 |
| 164 def _binaries_to_symbolize(self): | 167 def _binaries_to_symbolize(self): |
| 165 return ['lib/libcontent_shell_content_view.so'] | 168 return ['lib/libcontent_shell_content_view.so'] |
| 166 | 169 |
| 167 def _file_extension(self): | 170 def _file_extension(self): |
| 168 return 'dmp' | 171 return 'dmp' |
| OLD | NEW |