Chromium Code Reviews| Index: tools/findit/stacktrace.py |
| diff --git a/tools/findit/stacktrace.py b/tools/findit/stacktrace.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c1f139e6b74dd311e65b856b0af29e5f4bc1038d |
| --- /dev/null |
| +++ b/tools/findit/stacktrace.py |
| @@ -0,0 +1,173 @@ |
| +# Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +import os |
| +import re |
| +import findit_for_crash_utils as findit_utils |
|
stgao
2014/07/31 01:52:24
How about adding a file crash_utils.py? And includ
jeun
2014/07/31 18:41:15
Done.
|
| + |
| + |
| +class Stacktrace(object): |
|
stgao
2014/07/31 01:52:24
Rename to |StacktraceInfo|? Because it contains mu
jeun
2014/07/31 18:41:14
I named it stacktrace because this object exists o
stgao
2014/07/31 19:48:58
Sound good.
In that case, the comment "Contains re
|
| + """Represents Stacktrace object. |
| + |
| + Contains release build stacktrace and debug build stacktrace. |
| + """ |
| + |
| + def __init__(self, stacktrace, chrome_build): |
| + self.stack_list = [] |
| + self.ParseStacktrace(stacktrace, chrome_build) |
| + |
| + def ParseStacktrace(self, stacktrace, chrome_build): |
| + """Parses stacktrace and returns normalized stacktrace. |
|
stgao
2014/07/31 01:52:24
We do not return anything within this function act
jeun
2014/07/31 18:41:15
Done.
|
| + |
| + If there are multiple stack frames within the stacktrace, |
|
stgao
2014/07/31 01:52:24
What's the 'stack frame' here? Does it refer to a
jeun
2014/07/31 18:41:15
changed the description
|
| + it will parse each frame separately. |
| + |
| + Args: |
| + stacktrace: a string containing stacktrace |
| + chrome_build: a string containing the job type of the crash |
| + |
| + Returns: |
| + A stack dictionary, where key 'release' containing the result of parsing |
| + release build stacktrace and 'debug' containing the result from debug |
| + build stacktrace. Parsed result from each stacktrace contains a list |
| + of parsed result for each stack within the stacktrace, where a |
| + parsed result is a list of stacktraceline objects. |
| + """ |
| + # If the passed in string is empty, the object does not represent anything |
| + if not stacktrace: |
| + self.stack_list = None |
| + return |
| + |
| + stack_frame_index_pattern = re.compile(r'#\d+') |
| + |
| + # Reset the stack list, and assume we start from main thread |
|
stgao
2014/07/31 01:52:24
# Comments end with a period like this.
Please al
jeun
2014/07/31 18:41:15
Done.
|
| + self.stack_list = [] |
| + stack_priority = 0 |
| + seen_zero = False |
| + current_stack = CallStack(stack_priority) |
| + |
| + for line in stacktrace: |
| + |
| + # If this line does not represent the crashing information, continue |
| + if not stack_frame_index_pattern.match(line): |
| + continue |
| + |
| + # Get the frame index from the line |
| + parts = line.split() |
| + stack_frame_index = int(parts[0][1:]) |
|
stgao
2014/07/31 01:52:25
Use regex to get the stack_frame_index instead of
jeun
2014/07/31 18:41:15
Done.
|
| + |
| + # If it is 0, we need to check if this is from freed or prev-alloc, or |
| + # is from main thead |
| + if stack_frame_index == 0: |
| + |
| + # If this frame is from main thread |
|
stgao
2014/07/31 01:52:24
frame?
jeun
2014/07/31 18:41:15
Done.
|
| + if not seen_zero: |
|
stgao
2014/07/31 01:52:24
Could |seen_zero| be renamed to |seen_main_thread|
jeun
2014/07/31 18:41:15
Done.
|
| + seen_zero = True |
| + |
| + # If this is from freed or prev-alloc, add the callstack we have |
| + # to the list of callstacks, and increment the stack priority |
| + else: |
| + self.stack_list.append(current_stack) |
| + stack_priority += 1 |
| + current_stack = CallStack(stack_priority) |
| + |
| + # Parse function name, file path and line number from the line |
| + parsed_stack_frame_line = self.ExtractFromStacktraceLine( |
| + parts, chrome_build) |
| + |
| + # If the line is malformed, ignore this line. Else, get the info |
| + if not parsed_stack_frame_line: |
| + continue |
| + (function, file_path, crashed_line) = parsed_stack_frame_line |
| + |
| + # Normalize the file path so that it can be compared to repository path |
| + file_name = os.path.basename(file_path) |
| + (component, file_path) = findit_utils.NormalizePathLinux(file_path) |
| + |
| + # Currently supports only blink and chromium |
| + if component == 'blink' or component == 'chromium': |
| + current_stack.Add( |
| + StacktraceLine(stack_frame_index, component, file_name, |
| + function, file_path, crashed_line)) |
| + |
| + self.stack_list.append(current_stack) |
|
stgao
2014/07/31 01:52:24
I think different builds (asan, lsan, tsan, msan)
jeun
2014/07/31 18:41:14
I agree that something needs to be done about this
|
| + |
| + def ExtractFromStacktraceLine(self, parts, chrome_build): |
| + """Extracts information from stacktrace. |
|
stgao
2014/07/31 01:52:25
stacktrace seems misused here. Should be stack fra
jeun
2014/07/31 18:41:15
Done.
|
| + |
| + Args: |
| + parts: a list, stacktrace.split() |
| + chrome_build: a string containing the job type |
| + of this crash (e.g. linux_asan_chrome_mp) |
| + |
| + Returns: |
| + A triple containing the name of the function, the path of the file and |
| + the line of crash |
| + """ |
| + try: |
| + # tsan has different stack frame style from other builds |
| + if chrome_build.startswith('linux_tsan'): |
| + crash_component = parts[-2] |
|
stgao
2014/07/31 01:52:24
The way we guess |crash_component| here is hacky.
jeun
2014/07/31 18:41:15
This is just a totally mis named variable. changed
|
| + function = ' '.join(parts[1:-2]) |
| + |
| + else: |
| + crash_component = parts[-1] |
| + function = ' '.join(parts[3:-1]) |
| + |
| + # Get file path and line info from the line |
| + file_and_line = crash_component.split(':') |
| + file_path = file_and_line[0] |
| + crashed_line = int(file_and_line[1]) |
| + return (function, file_path, crashed_line) |
| + |
| + # Return None if the line is malformed |
| + except IndexError: |
| + return None |
| + except ValueError: |
| + return None |
| + |
| + def __getitem__(self, index): |
| + return self.stack_list[index] |
| + |
| + def GetStackFromMainThread(self): |
| + return self.stack_list[0] |
| + |
| + |
| +class CallStack(object): |
| + """Represents a call stack within a stacktrace. |
| + |
| + It is a list of stacktraceline object, and the stack represented by |
| + this object is from main thread, freed thread or previously-allocated thread. |
| + """ |
| + |
| + def __init__(self, stack_priority): |
| + self.line_list = [] |
|
stgao
2014/07/31 01:52:25
|line_list| -> |frames| or |frame_list|?
jeun
2014/07/31 18:41:15
Done.
|
| + self.priority = stack_priority |
| + |
| + def Add(self, stacktrace_line): |
| + self.line_list.append(stacktrace_line) |
| + |
| + def GetFirstN(self, n): |
|
stgao
2014/07/31 01:52:24
check out of boundary?
jeun
2014/07/31 18:41:15
Python automatically checks for boundary when usin
|
| + return self.line_list[:n] |
| + |
| + |
| +class StacktraceLine(object): |
| + """Represents a line in stacktrace. |
|
stgao
2014/07/31 01:52:25
We refer this as stack frames. Maybe renaming it t
jeun
2014/07/31 18:41:15
Done.
|
| + |
| + Attributes: |
| + stack_frame_index: index in the stacktrace |
| + component: a component this line represents, such as blink, chrome, etc. |
| + file_name: name of the file that crashed |
|
stgao
2014/07/31 01:52:24
|file_name| could be derived from |file_path|. Cou
jeun
2014/07/31 18:41:15
Same as the comment in component_dictionary file.
|
| + function: function that caused the crash |
| + file_path: path of the crashed file |
| + crashed_line: line of the file that caused the crash |
|
stgao
2014/07/31 01:52:25
Will |line_number| be more clear?
jeun
2014/07/31 18:41:15
changed to crashed_line_number
|
| + """ |
| + |
| + def __init__(self, stack_frame_index, component, file_name, |
| + function, file_path, crashed_line): |
| + self.stack_frame_index = stack_frame_index |
| + self.component = component |
| + self.file_name = file_name |
| + self.function = function |
| + self.file_path = file_path |
| + self.crashed_line = crashed_line |