OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
stgao
2014/08/01 17:22:21
It might be better to re-order the classes in this
jeun
2014/08/06 18:22:59
Reorder the classes as in reorder the order of imp
| |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import os | |
6 import re | |
7 import crash_utils | |
stgao
2014/08/01 17:22:21
One blank line between groups of imports.
For grou
jeun
2014/08/06 18:23:00
Done.
| |
8 | |
9 | |
10 class Stacktrace(object): | |
11 """Represents Stacktrace object. | |
12 | |
13 Contains a list of callstacks, because one stacktrace might have more than | |
14 one callstacks. | |
15 """ | |
16 | |
17 def __init__(self, stacktrace, chrome_build): | |
18 self.stack_list = [] | |
19 self.ParseStacktrace(stacktrace, chrome_build) | |
20 | |
21 def ParseStacktrace(self, stacktrace, chrome_build): | |
stgao
2014/08/01 17:22:21
I'm OK if you don't want to create a parser class
jeun
2014/08/06 18:23:00
Acknowledged.
| |
22 """Parses stacktrace and normalizes it. | |
23 | |
24 If there are multiple callstacks within the stacktrace, | |
25 it will parse each of them separately, and store them in the stack_list | |
26 variable. | |
27 | |
28 Args: | |
29 stacktrace: a string containing stacktrace | |
30 chrome_build: a string containing the job type of the crash | |
stgao
2014/08/01 17:22:21
Could we reword "job type" to "build type"? Same
jeun
2014/08/06 18:22:59
Done.
| |
31 """ | |
32 # If the passed in string is empty, the object does not represent anything. | |
33 if not stacktrace: | |
34 self.stack_list = None | |
35 return | |
36 | |
37 # Reset the stack list, and assume we start from main thread. | |
38 self.stack_list = [] | |
39 stack_priority = 0 | |
40 reached_new_callstack = False | |
41 # Note that we do not need exact stack frame index, we only need relative | |
42 # position of a frame within a callstack. The reason for not extracting | |
43 # index from a line is that some stack frames do not have index. | |
44 stack_frame_index = 0 | |
45 current_stack = CallStack(stack_priority) | |
46 | |
47 for line in stacktrace: | |
48 # Check if current line is the start of new callstack | |
49 is_new_callstack = self.CheckIfNewStackFrame(line, chrome_build) | |
stgao
2014/08/01 17:22:21
"CheckIfNewStackFrame" is not that clear. Based on
jeun
2014/08/06 18:22:59
Done.
| |
50 if is_new_callstack: | |
51 | |
52 # If this callstack is from main thread, update the boolean. | |
stgao
2014/08/01 17:22:21
Comment needs updating.
Please make sure comments
jeun
2014/08/06 18:22:59
I think this comment is correct. If it is new call
| |
53 if not reached_new_callstack: | |
54 reached_new_callstack = True | |
55 | |
56 # If this is from freed or prev-alloc, add the callstack we have | |
57 # to the list of callstacks, and increment the stack priority. | |
58 else: | |
59 stack_frame_index = 0 | |
60 self.stack_list.append(current_stack) | |
61 stack_priority += 1 | |
62 current_stack = CallStack(stack_priority) | |
63 | |
64 # Parse function name, file path and line number from the line. | |
65 parsed_stack_frame_line = self.__ExtractFromStackFrame( | |
66 line, chrome_build) | |
67 | |
68 # If the line is malformed, ignore this line. Else, get the info. | |
69 if not parsed_stack_frame_line: | |
70 continue | |
71 | |
72 (function, file_path, crashed_line_number) = parsed_stack_frame_line | |
73 | |
74 # Normalize the file path so that it can be compared to repository path. | |
75 file_name = os.path.basename(file_path) | |
76 (component, file_path) = crash_utils.NormalizePathLinux(file_path) | |
77 | |
78 # Currently supports only blink and chromium. | |
79 if component == 'blink' or component == 'chromium': | |
80 current_stack.Add( | |
81 StackFrame(stack_frame_index, component, file_name, | |
82 function, file_path, crashed_line_number)) | |
83 | |
84 stack_frame_index += 1 | |
85 | |
86 self.stack_list.append(current_stack) | |
stgao
2014/08/01 17:22:21
bug: if there is no frame found, an empty stack (i
jeun
2014/08/06 18:23:00
Done.
| |
87 | |
88 def CheckIfNewStackFrame(self, line, chrome_build): | |
stgao
2014/08/01 17:22:21
Will this function be used outside of this class?
jeun
2014/08/06 18:23:00
Renamed with two underscores.
| |
89 """Check if this line is the start of the new stack frame. | |
stgao
2014/08/01 17:22:21
why new stack frame?
jeun
2014/08/06 18:23:00
changed to callstack
| |
90 | |
91 Since each builds have different syntax of stacktrace, the logic for | |
stgao
2014/08/01 17:22:21
syntax -> format?
jeun
2014/08/06 18:23:00
Done.
| |
92 checking the line for all builds is handled in here. | |
93 | |
94 Args: | |
95 line: line to check for | |
96 chrome_build: the name of the build | |
97 | |
98 Returns: | |
99 True if the line is the start of new callstack, False otherwise | |
100 """ | |
101 # Currently not supported | |
102 if 'android' in chrome_build: | |
103 return False | |
104 | |
105 if 'syzyasan' in chrome_build: | |
106 # In syzyasan build, new stack starts with 'crash stack:', | |
107 # 'freed stack:', etc | |
108 callstack_start_pattern = re.compile(r'^.* stack:$') | |
109 return callstack_start_pattern.match(line) | |
110 | |
111 # Stack frame pattern for asan, lsan, tsan, etc | |
112 stack_frame_index_pattern = re.compile(r'#(\d+)') | |
113 | |
114 # Match the line to see if it is a valid stack frame. | |
115 stack_frame_index_match = stack_frame_index_pattern.match(line) | |
116 | |
117 # If this line does not represent the crashing information, continue. | |
stgao
2014/08/01 17:22:20
continue?
jeun
2014/08/06 18:23:00
changed to return false.
| |
118 if not stack_frame_index_match: | |
119 return False | |
120 | |
121 # Get index from the frame. If the index is 0, it means that new callstack | |
122 # starts in this line. | |
123 stack_frame_index = int(stack_frame_index_match.group(1)) | |
124 return stack_frame_index == 0 | |
125 | |
126 def __ExtractFromStackFrame(self, line, chrome_build): | |
127 """Extracts information from a line in stacktrace. | |
128 | |
129 Args: | |
130 line: a stacktrace string to extract data from | |
131 chrome_build: a string containing the job type | |
132 of this crash (e.g. linux_asan_chrome_mp) | |
133 | |
134 Returns: | |
135 A triple containing the name of the function, the path of the file and | |
136 the line of crash | |
stgao
2014/08/01 17:22:20
line content or line number?
jeun
2014/08/06 18:23:00
changed to crashed line number.
| |
137 """ | |
138 line_parts = line.split() | |
139 try: | |
140 # tsan has different stack frame style from other builds. | |
141 if chrome_build.startswith('linux_tsan'): | |
142 file_path_and_line = line_parts[-2] | |
143 function = ' '.join(line_parts[1:-2]) | |
144 | |
145 else: | |
146 file_path_and_line = line_parts[-1] | |
147 function = ' '.join(line_parts[3:-1]) | |
148 | |
149 # Get file path and line info from the line. | |
150 file_path_and_line = file_path_and_line.split(':') | |
151 file_path = file_path_and_line[0] | |
152 crashed_line_number = int(file_path_and_line[1]) | |
153 return (function, file_path, crashed_line_number) | |
154 | |
155 # Return None if the line is malformed. | |
156 except IndexError: | |
157 return None | |
158 except ValueError: | |
159 return None | |
160 | |
161 def __getitem__(self, index): | |
162 return self.stack_list[index] | |
163 | |
164 def GetStackFromMainThread(self): | |
stgao
2014/08/01 17:22:21
Is it true that the first callstack is from the ma
jeun
2014/08/06 18:23:00
I believe this is a valid assumption, from the sta
| |
165 return self.stack_list[0] | |
166 | |
167 | |
168 class CallStack(object): | |
169 """Represents a call stack within a stacktrace. | |
170 | |
171 It is a list of StackFrame object, and the stack represented by | |
172 this object is from main thread, freed thread or previously-allocated thread. | |
173 """ | |
174 | |
175 def __init__(self, stack_priority): | |
176 self.frame_list = [] | |
177 self.priority = stack_priority | |
178 | |
179 def Add(self, stacktrace_line): | |
180 self.frame_list.append(stacktrace_line) | |
181 | |
182 def GetFirstN(self, n): | |
183 return self.frame_list[:n] | |
184 | |
185 | |
186 class StackFrame(object): | |
187 """Represents a line in stacktrace. | |
stgao
2014/08/01 17:22:21
"a frame in callstack"?
jeun
2014/08/06 18:22:59
Done.
| |
188 | |
189 Attributes: | |
190 index: index in the stacktrace | |
191 component: a component this line represents, such as blink, chrome, etc. | |
192 file_name: name of the file that crashed | |
193 function: function that caused the crash | |
194 file_path: path of the crashed file | |
195 crashed_line_number: line of the file that caused the crash | |
196 """ | |
197 | |
198 def __init__(self, stack_frame_index, component, file_name, | |
199 function, file_path, crashed_line_number): | |
200 self.index = stack_frame_index | |
201 self.component = component | |
202 self.file_name = file_name | |
203 self.function = function | |
204 self.file_path = file_path | |
205 self.crashed_line_number = crashed_line_number | |
OLD | NEW |