Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 import os | |
| 5 import re | |
| 6 import crash_utils | |
| 7 | |
| 8 | |
| 9 class Stacktrace(object): | |
| 10 """Represents Stacktrace object. | |
| 11 | |
| 12 Contains release build stacktrace and debug build stacktrace. | |
| 13 """ | |
| 14 | |
| 15 def __init__(self, stacktrace, chrome_build): | |
| 16 self.stack_list = [] | |
| 17 self.ParseStacktrace(stacktrace, chrome_build) | |
| 18 | |
| 19 def ParseStacktrace(self, stacktrace, chrome_build): | |
| 20 """Parses stacktrace and normalizes it. | |
| 21 | |
| 22 If there are multiple callstacks within the stacktrace, | |
| 23 it will parse each of them separately, and store them in the stack_list | |
| 24 variable. | |
| 25 | |
| 26 Args: | |
| 27 stacktrace: a string containing stacktrace | |
| 28 chrome_build: a string containing the job type of the crash | |
| 29 """ | |
| 30 # If the passed in string is empty, the object does not represent anything. | |
| 31 if not stacktrace: | |
| 32 self.stack_list = None | |
| 33 return | |
| 34 | |
| 35 stack_frame_index_pattern = re.compile(r'#(\d+)') | |
| 36 | |
| 37 # Reset the stack list, and assume we start from main thread. | |
| 38 self.stack_list = [] | |
| 39 stack_priority = 0 | |
| 40 seen_main_thread = False | |
|
stgao
2014/07/31 19:48:58
reach_new_callstack?
| |
| 41 current_stack = CallStack(stack_priority) | |
| 42 | |
| 43 for line in stacktrace: | |
| 44 # match the line to see if it is a valid stack frame | |
|
stgao
2014/07/31 19:48:58
nit: comment style
| |
| 45 stack_frame_index_match = stack_frame_index_pattern.match(line) | |
| 46 | |
| 47 # If this line does not represent the crashing information, continue. | |
| 48 if not stack_frame_index_match: | |
| 49 continue | |
| 50 | |
| 51 # Get the stack frame index from the match | |
| 52 stack_frame_index = int(stack_frame_index_match.group(1)) | |
| 53 | |
| 54 # If it is 0, we need to check if this is from freed or prev-alloc, or | |
| 55 # is from main thead. | |
| 56 if stack_frame_index == 0: | |
| 57 | |
| 58 # If this callstack is from main thread, update the boolean. | |
| 59 if not seen_main_thread: | |
| 60 seen_main_thread = True | |
| 61 | |
| 62 # If this is from freed or prev-alloc, add the callstack we have | |
| 63 # to the list of callstacks, and increment the stack priority. | |
| 64 else: | |
| 65 self.stack_list.append(current_stack) | |
| 66 stack_priority += 1 | |
| 67 current_stack = CallStack(stack_priority) | |
| 68 | |
| 69 # Parse function name, file path and line number from the line. | |
| 70 parsed_stack_frame_line = self.ExtractFromStackFrame( | |
| 71 line, chrome_build) | |
| 72 | |
| 73 # If the line is malformed, ignore this line. Else, get the info. | |
| 74 if not parsed_stack_frame_line: | |
| 75 continue | |
| 76 (function, file_path, crashed_line_number) = parsed_stack_frame_line | |
| 77 | |
| 78 # Normalize the file path so that it can be compared to repository path. | |
| 79 file_name = os.path.basename(file_path) | |
| 80 (component, file_path) = crash_utils.NormalizePathLinux(file_path) | |
| 81 | |
| 82 # Currently supports only blink and chromium. | |
| 83 if component == 'blink' or component == 'chromium': | |
| 84 current_stack.Add( | |
| 85 StackFrame(stack_frame_index, component, file_name, | |
| 86 function, file_path, crashed_line_number)) | |
| 87 | |
| 88 self.stack_list.append(current_stack) | |
| 89 | |
| 90 def ExtractFromStackFrame(self, line, chrome_build): | |
|
stgao
2014/07/31 19:48:58
Used within class only. Add underscore before func
| |
| 91 """Extracts information from a line in stacktrace. | |
| 92 | |
| 93 Args: | |
| 94 line: a stacktrace string to extract data from | |
| 95 chrome_build: a string containing the job type | |
| 96 of this crash (e.g. linux_asan_chrome_mp) | |
| 97 | |
| 98 Returns: | |
| 99 A triple containing the name of the function, the path of the file and | |
| 100 the line of crash | |
| 101 """ | |
| 102 line_parts = line.split() | |
| 103 try: | |
| 104 # tsan has different stack frame style from other builds. | |
| 105 if chrome_build.startswith('linux_tsan'): | |
| 106 file_path_and_line = line_parts[-2] | |
| 107 function = ' '.join(line_parts[1:-2]) | |
| 108 | |
| 109 else: | |
| 110 file_path_and_line = line_parts[-1] | |
| 111 function = ' '.join(line_parts[3:-1]) | |
| 112 | |
| 113 # Get file path and line info from the line. | |
| 114 file_path_and_line = file_path_and_line.split(':') | |
| 115 file_path = file_path_and_line[0] | |
| 116 crashed_line_number = int(file_path_and_line[1]) | |
| 117 return (function, file_path, crashed_line_number) | |
| 118 | |
| 119 # Return None if the line is malformed. | |
| 120 except IndexError: | |
| 121 return None | |
| 122 except ValueError: | |
| 123 return None | |
| 124 | |
| 125 def __getitem__(self, index): | |
| 126 return self.stack_list[index] | |
| 127 | |
| 128 def GetStackFromMainThread(self): | |
| 129 return self.stack_list[0] | |
| 130 | |
| 131 | |
| 132 class CallStack(object): | |
| 133 """Represents a call stack within a stacktrace. | |
| 134 | |
| 135 It is a list of StackFrame object, and the stack represented by | |
| 136 this object is from main thread, freed thread or previously-allocated thread. | |
| 137 """ | |
| 138 | |
| 139 def __init__(self, stack_priority): | |
| 140 self.frame_list = [] | |
| 141 self.priority = stack_priority | |
| 142 | |
| 143 def Add(self, stacktrace_line): | |
| 144 self.frame_list.append(stacktrace_line) | |
| 145 | |
| 146 def GetFirstN(self, n): | |
| 147 return self.frame_list[:n] | |
| 148 | |
| 149 | |
| 150 class StackFrame(object): | |
| 151 """Represents a line in stacktrace. | |
| 152 | |
| 153 Attributes: | |
| 154 index: index in the stacktrace | |
| 155 component: a component this line represents, such as blink, chrome, etc. | |
| 156 file_name: name of the file that crashed | |
| 157 function: function that caused the crash | |
| 158 file_path: path of the crashed file | |
| 159 crashed_line_number: line of the file that caused the crash | |
| 160 """ | |
| 161 | |
| 162 def __init__(self, stack_frame_index, component, file_name, | |
| 163 function, file_path, crashed_line_number): | |
| 164 self.index = stack_frame_index | |
| 165 self.component = component | |
| 166 self.file_name = file_name | |
| 167 self.function = function | |
| 168 self.file_path = file_path | |
| 169 self.crashed_line_number = crashed_line_number | |
| OLD | NEW |