Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: tools/findit/stacktrace.py

Issue 430943003: [Findit] Plain objects to represent and parse stack trace. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed comments and changed variable names Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« tools/findit/crash_utils.py ('K') | « tools/findit/crash_utils.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
5 import os
6 import re
7
8 import crash_utils
9
10
11 class Stacktrace(object):
12 """Represents Stacktrace object.
13
14 Contains a list of callstacks, because one stacktrace might have more than
15 one callstacks.
16 """
17
18 def __init__(self, stacktrace, chrome_build):
19 self.stack_list = []
20 self.ParseStacktrace(stacktrace, chrome_build)
21
22 def ParseStacktrace(self, stacktrace, chrome_build):
23 """Parses stacktrace and normalizes it.
24
25 If there are multiple callstacks within the stacktrace,
26 it will parse each of them separately, and store them in the stack_list
27 variable.
28
29 Args:
30 stacktrace: A string containing stacktrace.
31 chrome_build: A string containing the build type of the crash.
32 """
33 # If the passed in string is empty, the object does not represent anything.
34 if not stacktrace:
35 self.stack_list = None
36 return
37
38 # Reset the stack list, and assume we start from main thread.
39 self.stack_list = []
40 stack_priority = 0
41 reached_new_callstack = False
42 # Note that we do not need exact stack frame index, we only need relative
43 # position of a frame within a callstack. The reason for not extracting
44 # index from a line is that some stack frames do not have index.
45 stack_frame_index = 0
46 current_stack = CallStack(stack_priority)
47
48 for line in stacktrace:
49 # Check if current line is the start of new callstack
Martin Barbella 2014/08/06 21:12:25 This comment isn't needed. The next line could sta
jeun 2014/08/06 23:36:25 Done.
50 is_new_callstack = self.__CheckIfNewCallStack(line, chrome_build)
Martin Barbella 2014/08/06 21:12:24 __CheckIfNewCallStack is a slightly awkward name.
jeun 2014/08/06 23:36:25 Done.
51 if is_new_callstack:
52
53 # If this callstack is from main thread, update the boolean.
54 if not reached_new_callstack:
55 reached_new_callstack = True
56
57 # If this is from freed or prev-alloc, add the callstack we have
58 # to the list of callstacks, and increment the stack priority.
59 else:
60 stack_frame_index = 0
61 if current_stack.frame_list:
62 self.stack_list.append(current_stack)
63 stack_priority += 1
Martin Barbella 2014/08/06 21:12:25 A while ago, I thought we discussed that free and
jeun 2014/08/06 23:36:25 i have fixed so that it would look at the marker w
64 current_stack = CallStack(stack_priority)
65
66 # Parse function name, file path and line number from the line.
67 parsed_stack_frame_line = self.__ExtractFromStackFrame(
Martin Barbella 2014/08/06 21:12:24 This is more of a general comment, but try to name
jeun 2014/08/06 23:36:25 Done.
68 line, chrome_build)
69
70 # If the line is malformed, ignore this line. Else, get the info.
71 if not parsed_stack_frame_line:
72 continue
73
74 (function, file_path, crashed_line_number) = parsed_stack_frame_line
Martin Barbella 2014/08/06 21:12:24 Instead of dealing with multiple return values fro
jeun 2014/08/06 23:36:25 Done.
75
76 # Normalize the file path so that it can be compared to repository path.
77 file_name = os.path.basename(file_path)
78 (component, file_path) = crash_utils.NormalizePathLinux(file_path)
79
80 # Currently supports only blink and chromium.
81 if component == 'blink' or component == 'chromium':
82 current_stack.Add(
83 StackFrame(stack_frame_index, component, file_name,
84 function, file_path, crashed_line_number))
85
86 stack_frame_index += 1
87
88 # Add the current callstack only if there are frames in it.
89 if current_stack.frame_list:
90 self.stack_list.append(current_stack)
91
92 def __CheckIfNewCallStack(self, line, chrome_build):
93 """Check if this line is the start of the new callstack.
94
95 Since each builds have different format of stacktrace, the logic for
96 checking the line for all builds is handled in here.
97
98 Args:
99 line: Line to check for.
100 chrome_build: The name of the build.
101
102 Returns:
103 True if the line is the start of new callstack, False otherwise.
104 """
105 # Currently not supported.
106 if 'android' in chrome_build:
107 return False
108
109 if 'syzyasan' in chrome_build:
110 # In syzyasan build, new stack starts with 'crash stack:',
111 # 'freed stack:', etc.
112 callstack_start_pattern = re.compile(r'^.* stack:$')
113 return callstack_start_pattern.match(line)
114
115 # Stack frame pattern for asan, lsan, tsan, etc.
116 stack_frame_index_pattern = re.compile(r'#(\d+)')
Martin Barbella 2014/08/06 21:12:25 Make sure that there is only whitespace before the
jeun 2014/08/06 23:36:25 This line is deleted.
117
118 # Match the line to see if it is a valid stack frame.
119 stack_frame_index_match = stack_frame_index_pattern.match(line)
120
121 # If this line does not represent the crashing information, return False.
122 if not stack_frame_index_match:
123 return False
124
125 # Get index from the frame. If the index is 0, it means that new callstack
126 # starts in this line.
127 stack_frame_index = int(stack_frame_index_match.group(1))
128 return stack_frame_index == 0
129
130 def __ExtractFromStackFrame(self, line, chrome_build):
131 """Extracts information from a line in stacktrace.
132
133 Args:
134 line: A stacktrace string to extract data from.
135 chrome_build: A string containing the build type
136 of this crash (e.g. linux_asan_chrome_mp).
137
138 Returns:
139 A triple containing the name of the function, the path of the file and
140 the crashed line number.
141 """
142 line_parts = line.split()
143 try:
144 # Tsan has different stack frame style from other builds.
145 if chrome_build.startswith('linux_tsan'):
146 # Filter out lines that are not stack frame.
147 stack_frame_index_pattern = re.compile(r'#(\d+)')
Martin Barbella 2014/08/06 21:12:25 These three lines seem to be the same in both case
jeun 2014/08/06 23:36:25 Done.
148 if not stack_frame_index_pattern.match(line_parts[0]):
149 return None
150
151 file_path_and_line = line_parts[-2]
152 function = ' '.join(line_parts[1:-2])
153
154 else:
155 # Filter out lines that are not stack frame.
156 stack_frame_index_pattern = re.compile(r'#(\d+)')
157 if not stack_frame_index_pattern.match(line_parts[0]):
158 return None
159
160 file_path_and_line = line_parts[-1]
161 function = ' '.join(line_parts[3:-1])
162
163 # Get file path and line info from the line.
164 file_path_and_line = file_path_and_line.split(':')
165 file_path = file_path_and_line[0]
166 crashed_line_number = int(file_path_and_line[1])
167 return (function, file_path, crashed_line_number)
168
169 # Return None if the line is malformed.
170 except IndexError:
171 return None
172 except ValueError:
173 return None
174
175 def __getitem__(self, index):
176 return self.stack_list[index]
177
178 def GetStackFromMainThread(self):
Martin Barbella 2014/08/06 21:12:25 It makes more sense to call this the crash stack t
jeun 2014/08/06 23:36:25 Done.
179 return self.stack_list[0]
180
181
182 class CallStack(object):
183 """Represents a call stack within a stacktrace.
184
185 It is a list of StackFrame object, and the stack represented by
186 this object is from main thread, freed thread or previously-allocated thread.
187 """
188
189 def __init__(self, stack_priority):
190 self.frame_list = []
191 self.priority = stack_priority
192
193 def Add(self, stacktrace_line):
194 self.frame_list.append(stacktrace_line)
195
196 def GetFirstN(self, n):
Martin Barbella 2014/08/06 21:12:24 Consider renaming to something like GetTopNFrames.
jeun 2014/08/06 23:36:25 Done.
197 return self.frame_list[:n]
198
199
200 class StackFrame(object):
201 """Represents a frame in stacktrace.
202
203 Attributes:
204 index: An index of the stack frame.
205 component: A component this line represents, such as blink, chrome, etc.
206 file_name: The name of the file that crashed.
207 function: The function that caused the crash.
208 file_path: The path of the crashed file.
209 crashed_line_number: The line of the file that caused the crash.
210 """
211
212 def __init__(self, stack_frame_index, component, file_name,
213 function, file_path, crashed_line_number):
214 self.index = stack_frame_index
215 self.component = component
216 self.file_name = file_name
217 self.function = function
218 self.file_path = file_path
219 self.crashed_line_number = crashed_line_number
OLDNEW
« tools/findit/crash_utils.py ('K') | « tools/findit/crash_utils.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698