Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 | 6 |
| 7 import chromium_deps | 7 import chromium_deps |
| 8 from common import utils | |
| 8 import crash_utils | 9 import crash_utils |
| 9 import findit_for_crash as findit | 10 import findit_for_crash as findit |
| 10 import stacktrace | 11 import stacktrace |
| 11 | 12 |
| 12 | 13 |
| 13 def SplitStacktrace(stacktrace_string): | 14 def SplitStacktrace(stacktrace_string): |
| 14 """Preprocesses stacktrace string into two parts, release and debug. | 15 """Preprocesses stacktrace string into two parts, release and debug. |
| 15 | 16 |
| 16 Args: | 17 Args: |
| 17 stacktrace_string: A string representation of stacktrace, | 18 stacktrace_string: A string representation of stacktrace, |
| 18 in clusterfuzz format. | 19 in clusterfuzz format. |
| 19 | 20 |
| 20 Returns: | 21 Returns: |
| 21 A tuple of list of strings, release build stacktrace and | 22 A tuple of list of strings, release build stacktrace and |
| 22 debug build stacktrace. | 23 debug build stacktrace. |
| 23 """ | 24 """ |
| 24 # Make sure we only parse release/debug build stacktrace, and ignore | 25 # Make sure we only parse release/debug build stacktrace, and ignore |
| 25 # unsymbolised stacktrace. | 26 # unsymbolised stacktrace. |
| 26 in_release_or_debug_stacktrace = False | 27 in_release_or_debug_stacktrace = False |
| 27 release_build_stacktrace_lines = None | 28 release_build_stacktrace_lines = None |
| 28 debug_build_stacktrace_lines = None | 29 debug_build_stacktrace_lines = None |
| 29 current_stacktrace_lines = [] | 30 current_stacktrace_lines = [] |
| 30 | 31 |
| 31 # Iterate through all lines in stacktrace. | 32 # Iterate through all lines in stacktrace. |
| 32 for line in stacktrace_string.splitlines(): | 33 for line in stacktrace_string.splitlines(): |
| 33 line = line.strip() | 34 line = line.strip() |
| 34 | 35 |
| 35 # If the line starts with +, it signifies the start of new stacktrace. | 36 # If the line starts with +, it signifies the start of new stacktrace. |
| 36 if line.startswith('+'): | 37 if line.startswith('+-') and line.endswith('-+'): |
| 37 if 'Release Build Stacktrace' in line: | 38 if 'Release Build Stacktrace' in line: |
| 38 in_release_or_debug_stacktrace = True | 39 in_release_or_debug_stacktrace = True |
| 39 current_stacktrace_lines = [] | 40 current_stacktrace_lines = [] |
| 40 release_build_stacktrace_lines = current_stacktrace_lines | 41 release_build_stacktrace_lines = current_stacktrace_lines |
| 41 | 42 |
| 42 elif 'Debug Build Stacktrace' in line: | 43 elif 'Debug Build Stacktrace' in line: |
| 43 in_release_or_debug_stacktrace = True | 44 in_release_or_debug_stacktrace = True |
| 44 current_stacktrace_lines = [] | 45 current_stacktrace_lines = [] |
| 45 debug_build_stacktrace_lines = current_stacktrace_lines | 46 debug_build_stacktrace_lines = current_stacktrace_lines |
| 46 | 47 |
| 47 # If the stacktrace is neither release/debug build stacktrace, ignore | 48 # If the stacktrace is neither release/debug build stacktrace, ignore |
| 48 # all lines after it until we encounter release/debug build stacktrace. | 49 # all lines after it until we encounter release/debug build stacktrace. |
| 49 else: | 50 else: |
| 50 in_release_or_debug_stacktrace = False | 51 in_release_or_debug_stacktrace = False |
| 51 | 52 |
| 52 # This case, it must be that the line is an actual stack frame, so add to | 53 # This case, it must be that the line is an actual stack frame, so add to |
| 53 # the current stacktrace. | 54 # the current stacktrace. |
| 54 elif in_release_or_debug_stacktrace: | 55 elif in_release_or_debug_stacktrace: |
| 55 current_stacktrace_lines.append(line) | 56 current_stacktrace_lines.append(line) |
| 56 | 57 |
| 57 return (release_build_stacktrace_lines, debug_build_stacktrace_lines) | 58 return (release_build_stacktrace_lines, debug_build_stacktrace_lines) |
| 58 | 59 |
| 59 | 60 |
| 60 def FindCulpritCLs(stacktrace_string, | 61 def FindCulpritCLs(stacktrace_string, |
| 61 build_type, | 62 build_type, |
| 62 chrome_regression=None, | 63 chrome_regression=None, |
| 63 component_regression=None, | 64 component_regression=None, |
| 64 chrome_crash_revision=None, | 65 chrome_crash_revision=None, |
| 65 component_crash_revision=None, | 66 component_crash_revision=None, |
| 66 crashing_component=None): | 67 crashing_component_path=None, |
| 68 crashing_component_name=None, | |
| 69 crashing_component_repo_url=None): | |
| 67 """Returns the result, a list of result.Result objects and message. | 70 """Returns the result, a list of result.Result objects and message. |
| 68 | 71 |
| 72 If either or both of component_regression and component_crash_revision is not | |
| 73 None, is is assumed that crashing_component_path and | |
| 74 crashing_component_repo_url are not None. | |
| 75 | |
| 69 Args: | 76 Args: |
| 70 stacktrace_string: A string representing stacktrace. | 77 stacktrace_string: A string representing stacktrace. |
| 71 build_type: The type of the job. | 78 build_type: The type of the job. |
| 72 chrome_regression: A string, chrome regression from clusterfuzz, in format | 79 chrome_regression: A string, chrome regression from clusterfuzz, in format |
| 73 '123456:123457' | 80 '123456:123457' |
| 74 component_regression: A string, component regression in the same format. | 81 component_regression: A string, component regression in the same format. |
| 75 chrome_crash_revision: A crash revision of chrome, in string. | 82 chrome_crash_revision: A crash revision of chrome, in string. |
| 76 component_crash_revision: A crash revision of the component, | 83 component_crash_revision: A crash revision of the component, |
| 77 if component build. | 84 if component build. |
| 78 crashing_component: Yet to be decided. | 85 crashing_component_path: A relative path of the crashing component, as in |
| 86 DEPS file. For example, it would be 'src/v8' for | |
| 87 v8 and 'src/third_party/WebKit' for blink. | |
| 88 crashing_component_name: A name of the crashing component, such as v8. | |
| 89 crashing_component_repo_url: The URL of the crashing component's repo, as | |
| 90 shown in DEPS file. For example, | |
| 91 'https://chromium.googlesource.com/skia.git' | |
| 92 for skia. | |
| 79 | 93 |
| 80 Returns: | 94 Returns: |
| 81 A list of result objects, along with the short description on where the | 95 A list of result objects, along with the short description on where the |
| 82 result is from. | 96 result is from. |
| 83 """ | 97 """ |
| 84 build_type = build_type.lower() | 98 build_type = build_type.lower() |
| 85 if 'syzyasan' in build_type: | |
| 86 return ('This build type is currently not supported.', []) | |
| 87 | |
| 88 logging.basicConfig(filename='errors.log', level=logging.WARNING, | 99 logging.basicConfig(filename='errors.log', level=logging.WARNING, |
| 89 filemode='w') | 100 filemode='w') |
| 90 | 101 |
| 91 component_to_crash_revision_dict = {} | 102 component_to_crash_revision_dict = {} |
| 92 component_to_regression_dict = {} | 103 component_to_regression_dict = {} |
| 93 | 104 |
| 94 # TODO(jeun): Come up with a good way to connect crashing component name to | |
| 95 # its path. | |
| 96 if component_regression or component_crash_revision: | |
| 97 return ('Component builds are not supported yet.', []) | |
| 98 | |
| 99 # If chrome regression is available, parse DEPS file. | 105 # If chrome regression is available, parse DEPS file. |
| 100 chrome_regression = crash_utils.SplitRange(chrome_regression) | 106 chrome_regression = crash_utils.SplitRange(chrome_regression) |
| 101 if chrome_regression: | 107 if chrome_regression: |
| 102 chrome_regression_start = chrome_regression[0] | 108 chrome_regression_start = chrome_regression[0] |
| 103 chrome_regression_end = chrome_regression[1] | 109 chrome_regression_end = chrome_regression[1] |
| 104 | 110 |
| 105 # Do not parse regression information for crashes introduced before the | 111 # Do not parse regression information for crashes introduced before the |
| 106 # first archived build. | 112 # first archived build. |
| 107 if chrome_regression_start != '0': | 113 if chrome_regression_start != '0': |
| 108 component_to_regression_dict = chromium_deps.GetChromiumComponentRange( | 114 component_to_regression_dict = chromium_deps.GetChromiumComponentRange( |
| 109 chrome_regression_start, chrome_regression_end) | 115 chrome_regression_start, chrome_regression_end) |
| 110 | 116 |
| 111 # Parse crash revision. | 117 # Parse crash revision. |
| 112 if chrome_crash_revision: | 118 if chrome_crash_revision: |
| 113 component_to_crash_revision_dict = chromium_deps.GetChromiumComponents( | 119 component_to_crash_revision_dict = chromium_deps.GetChromiumComponents( |
| 114 chrome_crash_revision) | 120 chrome_crash_revision) |
| 115 | 121 |
| 122 # Check if component regression information is available. | |
| 123 component_regression = crash_utils.SplitRange(component_regression) | |
| 124 if component_regression: | |
| 125 component_regression_start = component_regression[0] | |
| 126 component_regression_end = component_regression[1] | |
| 127 | |
| 128 # If this component already has an entry in parsed DEPS file, overwrite | |
| 129 # regression range and url. | |
| 130 if crashing_component_path in component_to_regression_dict: | |
| 131 component_regression_info = \ | |
| 132 component_to_regression_dict[crashing_component_path] | |
| 133 component_regression_info['old_revision'] = component_regression_start | |
| 134 component_regression_info['new_revision'] = component_regression_end | |
| 135 component_regression_info['repository'] = crashing_component_repo_url | |
| 136 | |
| 137 # if this component does not have an entry, add the entry to the parsed | |
| 138 # DEPS file. | |
| 139 else: | |
| 140 if utils.IsGitHash(component_regression_start): | |
|
Martin Barbella
2014/08/22 02:24:14
This pattern seems to come up a lot. Add a helper
jeun
2014/08/22 22:58:43
Done.
| |
| 141 repository_type = 'git' | |
| 142 else: | |
| 143 repository_type = 'svn' | |
| 144 | |
| 145 component_regression_info = { | |
| 146 'path': crashing_component_path, | |
| 147 'rolled': True, | |
| 148 'name': crashing_component_name, | |
| 149 'old_revision': component_regression_start, | |
| 150 'new_revision': component_regression_end, | |
| 151 'repository': crashing_component_repo_url, | |
| 152 'repository_type': repository_type | |
| 153 } | |
| 154 component_to_regression_dict[crashing_component_path] = \ | |
| 155 component_regression_info | |
| 156 | |
| 157 # If component crash revision is available, add it to the parsed crash | |
| 158 # revisions. | |
| 159 if component_crash_revision: | |
| 160 | |
| 161 # If this component has already a crash revision info, overwrite it. | |
| 162 if crashing_component_path in component_to_crash_revision_dict: | |
| 163 component_crash_revision_info = \ | |
| 164 component_to_crash_revision_dict[crashing_component_path] | |
| 165 component_crash_revision_info['revision'] = component_crash_revision | |
| 166 component_crash_revision_info['repository'] = crashing_component_repo_url | |
| 167 | |
| 168 # If not, add it to the parsed DEPS. | |
| 169 else: | |
| 170 if utils.IsGitHash(component_crash_revision): | |
| 171 repository_type = 'git' | |
| 172 else: | |
| 173 repository_type = 'svn' | |
| 174 component_crash_revision_info = { | |
| 175 'path': crashing_component_path, | |
| 176 'name': crashing_component_name, | |
| 177 'repository': crashing_component_repo_url, | |
| 178 'repository_type': repository_type, | |
| 179 'revision': component_crash_revision | |
| 180 } | |
| 181 component_to_crash_revision_dict[crashing_component_path] = \ | |
| 182 component_crash_revision_info | |
| 183 | |
| 116 # Parsed DEPS is used to normalize the stacktrace. Since parsed regression | 184 # Parsed DEPS is used to normalize the stacktrace. Since parsed regression |
| 117 # and parsed crash state essentially contain same information, use either. | 185 # and parsed crash state essentially contain same information, use either. |
| 118 if component_to_regression_dict: | 186 if component_to_regression_dict: |
| 119 parsed_deps = component_to_regression_dict | 187 parsed_deps = component_to_regression_dict |
| 120 elif component_to_crash_revision_dict: | 188 elif component_to_crash_revision_dict: |
| 121 parsed_deps = component_to_crash_revision_dict | 189 parsed_deps = component_to_crash_revision_dict |
| 122 else: | 190 else: |
| 123 return (('Identifying culprit CL requires at lease one of regression ' | 191 return (('Identifying culprit CL requires at lease one of regression ' |
| 124 'information or crash revision'), []) | 192 'information or crash revision'), []) |
| 125 | 193 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 140 main_stack = parsed_debug_build_stacktrace.GetCrashStack() | 208 main_stack = parsed_debug_build_stacktrace.GetCrashStack() |
| 141 else: | 209 else: |
| 142 return ('Stacktrace is malformed.', []) | 210 return ('Stacktrace is malformed.', []) |
| 143 | 211 |
| 144 # Run the algorithm on the parsed stacktrace, and return the result. | 212 # Run the algorithm on the parsed stacktrace, and return the result. |
| 145 stacktrace_list = [parsed_release_build_stacktrace, | 213 stacktrace_list = [parsed_release_build_stacktrace, |
| 146 parsed_debug_build_stacktrace] | 214 parsed_debug_build_stacktrace] |
| 147 return findit.FindItForCrash( | 215 return findit.FindItForCrash( |
| 148 stacktrace_list, main_stack, component_to_regression_dict, | 216 stacktrace_list, main_stack, component_to_regression_dict, |
| 149 component_to_crash_revision_dict) | 217 component_to_crash_revision_dict) |
| OLD | NEW |