| OLD | NEW |
| (Empty) |
| 1 # Copyright 2016 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 re | |
| 6 | |
| 7 from crash import parse_util | |
| 8 from crash.type_enums import CallStackFormatType, CallStackLanguageType | |
| 9 | |
| 10 # Used to parse a line into StackFrame of a Callstack. | |
| 11 CALLSTACK_FORMAT_TO_PATTERN = { | |
| 12 CallStackFormatType.JAVA: re.compile( | |
| 13 r'at ([A-Za-z0-9$._<>]+)\(\w+(\.java)?:(\d+)\)'), | |
| 14 CallStackFormatType.SYZYASAN: re.compile( | |
| 15 r'(CF: )?(.*?)( \(FPO: .*\) )?( \(CONV: .*\) )?\[(.*) @ (\d+)\]'), | |
| 16 CallStackFormatType.DEFAULT: re.compile( | |
| 17 r'(.*?):(\d+)(:\d+)?$') | |
| 18 } | |
| 19 | |
| 20 | |
| 21 FRAME_INDEX_PATTERN = re.compile(r'\s*#(\d+)\s.*') | |
| 22 | |
| 23 | |
| 24 class StackFrame(object): | |
| 25 """Represents a frame in a stacktrace. | |
| 26 | |
| 27 Attributes: | |
| 28 index (int): Index shown in the stacktrace if a stackframe line looks like | |
| 29 this - '#0 ...', else use the index in the callstack list. | |
| 30 dep_path (str): Path of the dep this frame represents, for example, | |
| 31 'src/', 'src/v8', 'src/skia'...etc. | |
| 32 function (str): Function that caused the crash. | |
| 33 file_path (str): Normalized path of the crashed file, with parts dep_path | |
| 34 and parts before it stripped, for example, api.cc. | |
| 35 raw_file_path (str): Normalized original path of the crashed file, | |
| 36 for example, /b/build/slave/mac64/build/src/v8/src/heap/ | |
| 37 incremental-marking-job.cc. | |
| 38 crashed_line_numbers (list): Line numbers of the file that caused the crash. | |
| 39 repo_url (str): Repo url of this frame. | |
| 40 """ | |
| 41 def __init__(self, index, dep_path, function, | |
| 42 file_path, raw_file_path, crashed_line_numbers, | |
| 43 repo_url=None): | |
| 44 self.index = index | |
| 45 self.dep_path = dep_path | |
| 46 self.function = function | |
| 47 self.file_path = file_path | |
| 48 self.raw_file_path = raw_file_path | |
| 49 self.crashed_line_numbers = crashed_line_numbers | |
| 50 self.repo_url = repo_url | |
| 51 | |
| 52 def ToString(self): | |
| 53 frame_str = '#%d in %s @ %s' % (self.index, self.function, self.file_path) | |
| 54 if self.crashed_line_numbers: | |
| 55 frame_str += ':%d' % self.crashed_line_numbers[0] | |
| 56 | |
| 57 # For example, if crashed_line_numbers is [61], returns '... f.cc:61', | |
| 58 # if is [61, 62], returns '... f.cc:61:1' | |
| 59 if len(self.crashed_line_numbers) > 1: | |
| 60 frame_str += ':%d' % (len(self.crashed_line_numbers) - 1) | |
| 61 | |
| 62 return frame_str | |
| 63 | |
| 64 def BlameUrl(self, revision): | |
| 65 if not self.repo_url or not self.dep_path: | |
| 66 return None | |
| 67 | |
| 68 blame_url = '%s/+blame/%s/%s' % (self.repo_url, revision, self.file_path) | |
| 69 if self.crashed_line_numbers: | |
| 70 blame_url += '#%d' % self.crashed_line_numbers[0] | |
| 71 | |
| 72 return blame_url | |
| 73 | |
| 74 def __str__(self): | |
| 75 return self.ToString() | |
| 76 | |
| 77 | |
| 78 class CallStack(list): | |
| 79 """Represents a call stack within a stacktrace. A list of StackFrame objects. | |
| 80 | |
| 81 Attributes: | |
| 82 priority (int): The smaller the number, the higher the priority beginning | |
| 83 with 0. | |
| 84 format_type (CallStackFormatType): Represents the type of line format | |
| 85 within a callstack. For example: | |
| 86 | |
| 87 CallStackFormatType.JAVA - | |
| 88 'at com.android.commands.am.Am.onRun(Am.java:353)' | |
| 89 | |
| 90 CallStackFormatType.SYZYASAN - | |
| 91 'chrome_child!v8::internal::ApplyTransition+0x93 [v8/src/lookup.cc @ 340]' | |
| 92 | |
| 93 CallStackFormatType.DEFAULT - | |
| 94 '#0 0x32b5982 in get third_party/WebKit/Source/wtf/RefPtr.h:61:43' | |
| 95 language_type (CallStackLanguageType): Either CPP or JAVA language. | |
| 96 """ | |
| 97 def __init__(self, priority, format_type=CallStackFormatType.DEFAULT, | |
| 98 language_type=CallStackLanguageType.CPP, | |
| 99 frame_list=None): | |
| 100 super(CallStack, self).__init__(frame_list or []) | |
| 101 | |
| 102 self.priority = priority | |
| 103 self.format_type = format_type | |
| 104 self.language_type = ( | |
| 105 CallStackLanguageType.JAVA if format_type == CallStackFormatType.JAVA | |
| 106 else language_type) | |
| 107 | |
| 108 def ParseLine(self, line, deps): | |
| 109 """Parse line into StackFrame instance and append it if successfully | |
| 110 parsed.""" | |
| 111 line = line.strip() | |
| 112 line_pattern = CALLSTACK_FORMAT_TO_PATTERN[self.format_type] | |
| 113 | |
| 114 if self.format_type == CallStackFormatType.JAVA: | |
| 115 match = line_pattern.match(line) | |
| 116 if not match: | |
| 117 return | |
| 118 | |
| 119 function = match.group(1) | |
| 120 raw_file_path = parse_util.GetFullPathForJavaFrame(function) | |
| 121 crashed_line_numbers = [int(match.group(3))] | |
| 122 | |
| 123 elif self.format_type == CallStackFormatType.SYZYASAN: | |
| 124 match = line_pattern.match(line) | |
| 125 if not match: | |
| 126 return | |
| 127 | |
| 128 function = match.group(2).strip() | |
| 129 raw_file_path = match.group(5) | |
| 130 crashed_line_numbers = [int(match.group(6))] | |
| 131 | |
| 132 else: | |
| 133 line_parts = line.split() | |
| 134 if not line_parts or not line_parts[0].startswith('#'): | |
| 135 return | |
| 136 | |
| 137 match = line_pattern.match(line_parts[-1]) | |
| 138 if not match: | |
| 139 return | |
| 140 | |
| 141 function = ' '.join(line_parts[3:-1]) | |
| 142 | |
| 143 raw_file_path = match.group(1) | |
| 144 # Fracas java stack has default format type. | |
| 145 if self.language_type == CallStackLanguageType.JAVA: | |
| 146 raw_file_path = parse_util.GetFullPathForJavaFrame(function) | |
| 147 | |
| 148 crashed_line_numbers = parse_util.GetCrashedLineRange( | |
| 149 match.group(2) + (match.group(3) if match.group(3) else '')) | |
| 150 # Normalize the file path so that it can be compared to repository path. | |
| 151 dep_path, file_path, repo_url = parse_util.GetDepPathAndNormalizedFilePath( | |
| 152 raw_file_path, deps, self.language_type == CallStackLanguageType.JAVA) | |
| 153 | |
| 154 # If we have the common stack frame index pattern, then use it | |
| 155 # since it is more reliable. | |
| 156 index_match = FRAME_INDEX_PATTERN.match(line) | |
| 157 if index_match: | |
| 158 stack_frame_index = int(index_match.group(1)) | |
| 159 else: | |
| 160 stack_frame_index = len(self) | |
| 161 | |
| 162 self.append(StackFrame(stack_frame_index, dep_path, function, file_path, | |
| 163 raw_file_path, crashed_line_numbers, repo_url)) | |
| OLD | NEW |