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 |