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

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: Added functionality in stacktrace to easily add new parse rules for different chrome builds 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.
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
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