| 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.type_enums import CallStackFormatType |
| 8 from crash.type_enums import LanguageType |
| 9 from crash.type_enums import SanitizerType |
| 10 |
| 11 |
| 12 class CallStackDetector(object): |
| 13 """Class for detecting the start of a particular sort of CallStack.""" |
| 14 |
| 15 # TODO(crbug.com/677321) Make the return to be a namedtuple. |
| 16 def IsStartOfNewCallStack(self, line, flags=None): |
| 17 """Determines whether a line is the start of a new callstack or not. |
| 18 |
| 19 Args: |
| 20 line (str): The line to be checked. |
| 21 flags (FlagManager): manager for keeping track of parsing flags. |
| 22 |
| 23 Returns: |
| 24 A tuple - |
| 25 (is_new_callstack, priority, format_type, language_type, metadata) |
| 26 is_new_callstack (bool): Boolean indicating whether this is the start of |
| 27 a new callstack. |
| 28 priority (int): Priority of a callstack. |
| 29 format_type (CallStackFormatType): The format of the new callstack, or |
| 30 None if there is no new callstack. |
| 31 language_type (LanguageType): The language of the new callstack, or None |
| 32 if there is no new callstack. |
| 33 metadata (dict): Dict of metadata for the new callstack, e.g. pid of |
| 34 the stack. |
| 35 """ |
| 36 raise NotImplementedError() |
| 37 |
| 38 |
| 39 class AndroidJobDetector(CallStackDetector): |
| 40 """Detects the start of an android job callstack.""" |
| 41 JAVA_LANG_CALLSTACK_START_PATTERN = r'^java\.[A-Za-z0-9$._]+' |
| 42 JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN = r'^org\.chromium\.[A-Za-z0-9$._]+' |
| 43 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN = r'^Caused by:' |
| 44 JAVA_ANDROID_CALLSTACK_START_PATTERN = ( |
| 45 r'^(com\.google\.)?android\.[A-Za-z0-9$._]+') |
| 46 |
| 47 JAVA_CALLSTACK_START_REGEX = re.compile( |
| 48 '|'.join([JAVA_LANG_CALLSTACK_START_PATTERN, |
| 49 JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN, |
| 50 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN, |
| 51 JAVA_ANDROID_CALLSTACK_START_PATTERN])) |
| 52 |
| 53 def IsStartOfNewCallStack(self, line, flags=None): |
| 54 if AndroidJobDetector.JAVA_CALLSTACK_START_REGEX.match(line): |
| 55 # Only assign the highest priority to fatal exception stack or segv |
| 56 # stack. |
| 57 if flags and flags.Get('java_main_stack_flag'): |
| 58 flags.TurnOff('java_main_stack_flag') |
| 59 return True, 0, CallStackFormatType.JAVA, LanguageType.JAVA, {} |
| 60 |
| 61 return True, 1, CallStackFormatType.JAVA, LanguageType.JAVA, {} |
| 62 |
| 63 return False, None, None, None, None |
| 64 |
| 65 |
| 66 class SyzyasanDetector(CallStackDetector): |
| 67 """Detects the start of a syzyasn callstack.""" |
| 68 SYZYASAN_CRASH_CALLSTACK_START_REGEX = re.compile(r'^Crash stack:$') |
| 69 SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(r'^(?!Crash).* stack:$') |
| 70 |
| 71 def IsStartOfNewCallStack(self, line, flags=None): |
| 72 # In syzyasan build, new stack starts with 'crash stack:', |
| 73 # 'freed stack:', etc. |
| 74 if SyzyasanDetector.SYZYASAN_CRASH_CALLSTACK_START_REGEX.match(line): |
| 75 return True, 0, CallStackFormatType.SYZYASAN, LanguageType.CPP, {} |
| 76 # Other callstacks all get priority 1. |
| 77 if SyzyasanDetector.SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX.match(line): |
| 78 return True, 1, CallStackFormatType.SYZYASAN, LanguageType.CPP, {} |
| 79 |
| 80 return False, None, None, None, None |
| 81 |
| 82 |
| 83 class TsanDetector(CallStackDetector): |
| 84 """Detects the start of a thread sanitizer callstack.""" |
| 85 TSAN_CRASH_CALLSTACK_START_PATTERN1 = r'^(Read|Write) of size \d+' |
| 86 TSAN_CRASH_CALLSTACK_START_PATTERN2 = r'^[A-Z]+: ThreadSanitizer' |
| 87 TSAN_ALLOCATION_CALLSTACK_START_PATTERN = ( |
| 88 r'^Previous (write|read) of size \d+') |
| 89 TSAN_LOCATION_CALLSTACK_START_PATTERN = ( |
| 90 r'^Location is heap block of size \d+') |
| 91 |
| 92 TSAN_CRASH_CALLSTACK_START_REGEX = re.compile( |
| 93 '|'.join([TSAN_CRASH_CALLSTACK_START_PATTERN1, |
| 94 TSAN_CRASH_CALLSTACK_START_PATTERN2])) |
| 95 |
| 96 TSAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile( |
| 97 '|'.join([TSAN_ALLOCATION_CALLSTACK_START_PATTERN, |
| 98 TSAN_LOCATION_CALLSTACK_START_PATTERN])) |
| 99 |
| 100 def IsStartOfNewCallStack(self, line, flags=None): |
| 101 # Crash stack gets priority 0. |
| 102 if TsanDetector.TSAN_CRASH_CALLSTACK_START_REGEX.match(line): |
| 103 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 104 |
| 105 # All other stacks get priority 1. |
| 106 if TsanDetector.TSAN_NON_CRASH_CALLSTACK_START_REGEX.match(line): |
| 107 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 108 |
| 109 return False, None, None, None, None |
| 110 |
| 111 |
| 112 class UbsanDetector(CallStackDetector): |
| 113 """Detects the start of an undefined-behavior callstack.""" |
| 114 UBSAN_CALLSTACK_START_REGEX = re.compile(r'^.*: runtime error: .*$') |
| 115 |
| 116 def IsStartOfNewCallStack(self, line, flags=None): |
| 117 if UbsanDetector.UBSAN_CALLSTACK_START_REGEX.match(line): |
| 118 if flags and flags.Get('is_first_stack_flag'): |
| 119 flags.TurnOff('is_first_stack_flag') |
| 120 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 121 |
| 122 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 123 |
| 124 return False, None, None, None, None |
| 125 |
| 126 |
| 127 class MsanDetector(CallStackDetector): |
| 128 """Detects the start of a memory sanitizer callstack.""" |
| 129 MSAN_CALLSTACK_START_REGEX = re.compile(r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)') |
| 130 MSAN_CREATION_CALLSTACK_START_MARKER = 'Uninitialized value was created by' |
| 131 MSAN_STORAGE_CALLSTACK_START_MARKER = 'Uninitialized value was stored to' |
| 132 |
| 133 def IsStartOfNewCallStack(self, line, flags=None): |
| 134 # Assign the only msan stack priority 0. |
| 135 if MsanDetector.MSAN_CREATION_CALLSTACK_START_MARKER in line: |
| 136 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 137 if MsanDetector.MSAN_STORAGE_CALLSTACK_START_MARKER in line: |
| 138 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 139 msan_callstack_start_regex = ( |
| 140 MsanDetector.MSAN_CALLSTACK_START_REGEX.match(line)) |
| 141 if msan_callstack_start_regex: |
| 142 return (True, 2, CallStackFormatType.DEFAULT, LanguageType.CPP, |
| 143 {'pid': int(msan_callstack_start_regex.group(1).strip())}) |
| 144 |
| 145 return False, None, None, None, None |
| 146 |
| 147 |
| 148 class AsanDetector(CallStackDetector): |
| 149 """Detects the start of an address sanitizer callstack.""" |
| 150 ASAN_CRASH_CALLSTACK_START_REGEX1 = re.compile( |
| 151 r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)') |
| 152 ASAN_CRASH_CALLSTACK_START_REGEX2 = re.compile( |
| 153 r'^(READ|WRITE) of size \d+ at|^backtrace:') |
| 154 |
| 155 ASAN_FREED_CALLSTACK_START_PATTERN = ( |
| 156 r'^freed by thread T\d+ (.* )?here:') |
| 157 ASAN_ALLOCATION_CALLSTACK_START_PATTERN = ( |
| 158 r'^(previously )?allocated by thread T\d+ (.* )?here:') |
| 159 ASAN_OTHER_CALLSTACK_START_PATTERN = ( |
| 160 r'^Thread T\d+ (.* )?created by') |
| 161 |
| 162 ASAN_NON_CRASH_CALLSTACK_START_PATTERN = re.compile( |
| 163 '|'.join([ASAN_FREED_CALLSTACK_START_PATTERN, |
| 164 ASAN_ALLOCATION_CALLSTACK_START_PATTERN, |
| 165 ASAN_OTHER_CALLSTACK_START_PATTERN])) |
| 166 |
| 167 def IsStartOfNewCallStack(self, line, flags=None): |
| 168 asan_crash_callstack_start_regex1_match = ( |
| 169 AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX1.match(line)) |
| 170 if asan_crash_callstack_start_regex1_match: |
| 171 return (True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, |
| 172 {'pid': int( |
| 173 asan_crash_callstack_start_regex1_match.group(1).strip())}) |
| 174 |
| 175 # Crash stack gets priority 0. |
| 176 if AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX2.match(line): |
| 177 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 178 |
| 179 # All other callstack gets priority 1. |
| 180 if AsanDetector.ASAN_NON_CRASH_CALLSTACK_START_PATTERN.match(line): |
| 181 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 182 |
| 183 return False, None, None, None, None |
| 184 |
| 185 |
| 186 class ChromeCrashStackDetector(CallStackDetector): |
| 187 """Detects the start of an chromecrash(Fracas/Cracas) callstack.""" |
| 188 CHROME_CRASH_CALLSTACK_START_REGEX = re.compile(r'CRASHED \[(.*) @ 0x(.*)\]') |
| 189 JAVA_CALLSTACK_START_REGEX = re.compile(r'\(JAVA\) CRASHED \[(.*) @ 0x(.*)\]') |
| 190 |
| 191 def IsStartOfNewCallStack(self, line, flags=None): |
| 192 if ChromeCrashStackDetector.CHROME_CRASH_CALLSTACK_START_REGEX.match(line): |
| 193 # Fracas only provide magic signature stack (crash stack). |
| 194 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} |
| 195 |
| 196 if ChromeCrashStackDetector.JAVA_CALLSTACK_START_REGEX.match(line): |
| 197 return True, 0, CallStackFormatType.DEFAULT, LanguageType.JAVA, {} |
| 198 |
| 199 return False, None, None, None, None |
| OLD | NEW |