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

Side by Side Diff: appengine/findit/crash/callstack_detectors.py

Issue 2607813002: [Predator] Make ``CallStackDetector`` return a namedtuple. (Closed)
Patch Set: Rebase and fix nit. Created 3 years, 11 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
« no previous file with comments | « no previous file | appengine/findit/crash/chromecrash_parser.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from collections import namedtuple
5 import re 6 import re
6 7
7 from crash.type_enums import CallStackFormatType 8 from crash.type_enums import CallStackFormatType
8 from crash.type_enums import LanguageType 9 from crash.type_enums import LanguageType
9 from crash.type_enums import SanitizerType 10 from crash.type_enums import SanitizerType
10 11
11 12
13 class StartOfCallStack(
14 namedtuple('StartOfCallStack',
15 ['priority', 'format_type', 'language_type', 'metadata'])):
16 """Represents the start of a new callstack.
17
18 Properties:
19 priority (int): Priority of the new callstack.
20 format_type (CallStackFormatType): The format of the new callstack.
21 language_type (LanguageType): The language of the new callstack.
22 metadata (dict): Dict of metadata for the new callstack, e.g. pid of the
23 stack.
24 """
25 __slots__ = ()
26
27 def __new__(cls, priority, format_type, language_type, metadata=None):
28 return super(cls, StartOfCallStack).__new__(cls, priority, format_type,
29 language_type, metadata or {})
30
31 def __str__(self): # pragma: no cover
32 return ('%s(priority = %d, format_type = %d, '
33 'language_type = %d, metadata = %s)' % (self.__class__.__name__,
34 self.priority,
35 self.format_type,
36 self.language_type,
37 self.metadata))
38
39
12 class CallStackDetector(object): 40 class CallStackDetector(object):
13 """Class for detecting the start of a particular sort of CallStack.""" 41 """Class for detecting the start of a particular sort of CallStack."""
14 42
15 # TODO(crbug.com/677321) Make the return to be a namedtuple. 43 def __call__(self, line, flags=None):
16 def IsStartOfNewCallStack(self, line, flags=None):
17 """Determines whether a line is the start of a new callstack or not. 44 """Determines whether a line is the start of a new callstack or not.
18 45
19 Args: 46 Args:
20 line (str): The line to be checked. 47 line (str): The line to be checked.
21 flags (FlagManager): manager for keeping track of parsing flags. 48 flags (FlagManager): manager for keeping track of parsing flags.
22 49
23 Returns: 50 Returns:
24 A tuple - 51 A ``StartOfCallStack`` or None if no callstack found.
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 """ 52 """
36 raise NotImplementedError() 53 raise NotImplementedError()
37 54
38 55
39 class AndroidJobDetector(CallStackDetector): 56 class AndroidJobDetector(CallStackDetector):
40 """Detects the start of an android job callstack.""" 57 """Detects the start of an android job callstack."""
41 JAVA_LANG_CALLSTACK_START_PATTERN = r'^java\.[A-Za-z0-9$._]+' 58 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$._]+' 59 JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN = r'^org\.chromium\.[A-Za-z0-9$._]+'
43 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN = r'^Caused by:' 60 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN = r'^Caused by:'
44 JAVA_ANDROID_CALLSTACK_START_PATTERN = ( 61 JAVA_ANDROID_CALLSTACK_START_PATTERN = (
45 r'^(com\.google\.)?android\.[A-Za-z0-9$._]+') 62 r'^(com\.google\.)?android\.[A-Za-z0-9$._]+')
46 63
47 JAVA_CALLSTACK_START_REGEX = re.compile( 64 JAVA_CALLSTACK_START_REGEX = re.compile(
48 '|'.join([JAVA_LANG_CALLSTACK_START_PATTERN, 65 '|'.join([JAVA_LANG_CALLSTACK_START_PATTERN,
49 JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN, 66 JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN,
50 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN, 67 JAVA_CAUSED_BY_CALLSTACK_START_PATTERN,
51 JAVA_ANDROID_CALLSTACK_START_PATTERN])) 68 JAVA_ANDROID_CALLSTACK_START_PATTERN]))
52 69
53 def IsStartOfNewCallStack(self, line, flags=None): 70 def __call__(self, line, flags=None):
54 if AndroidJobDetector.JAVA_CALLSTACK_START_REGEX.match(line): 71 if AndroidJobDetector.JAVA_CALLSTACK_START_REGEX.match(line):
55 # Only assign the highest priority to fatal exception stack or segv 72 # Only assign the highest priority to fatal exception stack or segv
56 # stack. 73 # stack.
57 if flags and flags.Get('java_main_stack_flag'): 74 if flags and flags.Get('java_main_stack_flag'):
58 flags.TurnOff('java_main_stack_flag') 75 flags.TurnOff('java_main_stack_flag')
59 return True, 0, CallStackFormatType.JAVA, LanguageType.JAVA, {} 76 return StartOfCallStack(0, CallStackFormatType.JAVA,
77 LanguageType.JAVA, {})
60 78
61 return True, 1, CallStackFormatType.JAVA, LanguageType.JAVA, {} 79 return StartOfCallStack(1, CallStackFormatType.JAVA,
80 LanguageType.JAVA, {})
62 81
63 return False, None, None, None, None 82 return None
64 83
65 84
66 class SyzyasanDetector(CallStackDetector): 85 class SyzyasanDetector(CallStackDetector):
67 """Detects the start of a syzyasn callstack.""" 86 """Detects the start of a syzyasn callstack."""
68 SYZYASAN_CRASH_CALLSTACK_START_REGEX = re.compile(r'^Crash stack:$') 87 SYZYASAN_CRASH_CALLSTACK_START_REGEX = re.compile(r'^Crash stack:$')
69 SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(r'^(?!Crash).* stack:$') 88 SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(r'^(?!Crash).* stack:$')
70 89
71 def IsStartOfNewCallStack(self, line, flags=None): 90 def __call__(self, line, flags=None):
72 # In syzyasan build, new stack starts with 'crash stack:', 91 # In syzyasan build, new stack starts with 'crash stack:',
73 # 'freed stack:', etc. 92 # 'freed stack:', etc.
74 if SyzyasanDetector.SYZYASAN_CRASH_CALLSTACK_START_REGEX.match(line): 93 if SyzyasanDetector.SYZYASAN_CRASH_CALLSTACK_START_REGEX.match(line):
75 return True, 0, CallStackFormatType.SYZYASAN, LanguageType.CPP, {} 94 return StartOfCallStack(0, CallStackFormatType.SYZYASAN,
95 LanguageType.CPP, {})
76 # Other callstacks all get priority 1. 96 # Other callstacks all get priority 1.
77 if SyzyasanDetector.SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX.match(line): 97 if SyzyasanDetector.SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX.match(line):
78 return True, 1, CallStackFormatType.SYZYASAN, LanguageType.CPP, {} 98 return StartOfCallStack(1, CallStackFormatType.SYZYASAN,
99 LanguageType.CPP, {})
79 100
80 return False, None, None, None, None 101 return None
81 102
82 103
83 class TsanDetector(CallStackDetector): 104 class TsanDetector(CallStackDetector):
84 """Detects the start of a thread sanitizer callstack.""" 105 """Detects the start of a thread sanitizer callstack."""
85 TSAN_CRASH_CALLSTACK_START_PATTERN1 = r'^(Read|Write) of size \d+' 106 TSAN_CRASH_CALLSTACK_START_PATTERN1 = r'^(Read|Write) of size \d+'
86 TSAN_CRASH_CALLSTACK_START_PATTERN2 = r'^[A-Z]+: ThreadSanitizer' 107 TSAN_CRASH_CALLSTACK_START_PATTERN2 = r'^[A-Z]+: ThreadSanitizer'
87 TSAN_ALLOCATION_CALLSTACK_START_PATTERN = ( 108 TSAN_ALLOCATION_CALLSTACK_START_PATTERN = (
88 r'^Previous (write|read) of size \d+') 109 r'^Previous (write|read) of size \d+')
89 TSAN_LOCATION_CALLSTACK_START_PATTERN = ( 110 TSAN_LOCATION_CALLSTACK_START_PATTERN = (
90 r'^Location is heap block of size \d+') 111 r'^Location is heap block of size \d+')
91 112
92 TSAN_CRASH_CALLSTACK_START_REGEX = re.compile( 113 TSAN_CRASH_CALLSTACK_START_REGEX = re.compile(
93 '|'.join([TSAN_CRASH_CALLSTACK_START_PATTERN1, 114 '|'.join([TSAN_CRASH_CALLSTACK_START_PATTERN1,
94 TSAN_CRASH_CALLSTACK_START_PATTERN2])) 115 TSAN_CRASH_CALLSTACK_START_PATTERN2]))
95 116
96 TSAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile( 117 TSAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(
97 '|'.join([TSAN_ALLOCATION_CALLSTACK_START_PATTERN, 118 '|'.join([TSAN_ALLOCATION_CALLSTACK_START_PATTERN,
98 TSAN_LOCATION_CALLSTACK_START_PATTERN])) 119 TSAN_LOCATION_CALLSTACK_START_PATTERN]))
99 120
100 def IsStartOfNewCallStack(self, line, flags=None): 121 def __call__(self, line, flags=None):
101 # Crash stack gets priority 0. 122 # Crash stack gets priority 0.
102 if TsanDetector.TSAN_CRASH_CALLSTACK_START_REGEX.match(line): 123 if TsanDetector.TSAN_CRASH_CALLSTACK_START_REGEX.match(line):
103 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 124 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
125 LanguageType.CPP, {})
104 126
105 # All other stacks get priority 1. 127 # All other stacks get priority 1.
106 if TsanDetector.TSAN_NON_CRASH_CALLSTACK_START_REGEX.match(line): 128 if TsanDetector.TSAN_NON_CRASH_CALLSTACK_START_REGEX.match(line):
107 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 129 return StartOfCallStack(1, CallStackFormatType.DEFAULT,
130 LanguageType.CPP, {})
108 131
109 return False, None, None, None, None 132 return None
110 133
111 134
112 class UbsanDetector(CallStackDetector): 135 class UbsanDetector(CallStackDetector):
113 """Detects the start of an undefined-behavior callstack.""" 136 """Detects the start of an undefined-behavior callstack."""
114 UBSAN_CALLSTACK_START_REGEX = re.compile(r'^.*: runtime error: .*$') 137 UBSAN_CALLSTACK_START_REGEX = re.compile(r'^.*: runtime error: .*$')
115 138
116 def IsStartOfNewCallStack(self, line, flags=None): 139 def __call__(self, line, flags=None):
117 if UbsanDetector.UBSAN_CALLSTACK_START_REGEX.match(line): 140 if UbsanDetector.UBSAN_CALLSTACK_START_REGEX.match(line):
118 if flags and flags.Get('is_first_stack_flag'): 141 if flags and flags.Get('is_first_stack_flag'):
119 flags.TurnOff('is_first_stack_flag') 142 flags.TurnOff('is_first_stack_flag')
120 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 143 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
144 LanguageType.CPP, {})
121 145
122 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 146 return StartOfCallStack(1, CallStackFormatType.DEFAULT,
147 LanguageType.CPP, {})
123 148
124 return False, None, None, None, None 149 return None
125 150
126 151
127 class MsanDetector(CallStackDetector): 152 class MsanDetector(CallStackDetector):
128 """Detects the start of a memory sanitizer callstack.""" 153 """Detects the start of a memory sanitizer callstack."""
129 MSAN_CALLSTACK_START_REGEX = re.compile(r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)') 154 MSAN_CALLSTACK_START_REGEX = re.compile(r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)')
130 MSAN_CREATION_CALLSTACK_START_MARKER = 'Uninitialized value was created by' 155 MSAN_CREATION_CALLSTACK_START_MARKER = 'Uninitialized value was created by'
131 MSAN_STORAGE_CALLSTACK_START_MARKER = 'Uninitialized value was stored to' 156 MSAN_STORAGE_CALLSTACK_START_MARKER = 'Uninitialized value was stored to'
132 157
133 def IsStartOfNewCallStack(self, line, flags=None): 158 def __call__(self, line, flags=None):
134 # Assign the only msan stack priority 0. 159 # Assign the only msan stack priority 0.
135 if MsanDetector.MSAN_CREATION_CALLSTACK_START_MARKER in line: 160 if MsanDetector.MSAN_CREATION_CALLSTACK_START_MARKER in line:
136 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 161 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
162 LanguageType.CPP, {})
137 if MsanDetector.MSAN_STORAGE_CALLSTACK_START_MARKER in line: 163 if MsanDetector.MSAN_STORAGE_CALLSTACK_START_MARKER in line:
138 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 164 return StartOfCallStack(1, CallStackFormatType.DEFAULT,
165 LanguageType.CPP, {})
139 msan_callstack_start_regex = ( 166 msan_callstack_start_regex = (
140 MsanDetector.MSAN_CALLSTACK_START_REGEX.match(line)) 167 MsanDetector.MSAN_CALLSTACK_START_REGEX.match(line))
141 if msan_callstack_start_regex: 168 if msan_callstack_start_regex:
142 return (True, 2, CallStackFormatType.DEFAULT, LanguageType.CPP, 169 return StartOfCallStack(
143 {'pid': int(msan_callstack_start_regex.group(1).strip())}) 170 2, CallStackFormatType.DEFAULT, LanguageType.CPP,
171 {'pid': int(msan_callstack_start_regex.group(1).strip())})
144 172
145 return False, None, None, None, None 173 return None
146 174
147 175
148 class AsanDetector(CallStackDetector): 176 class AsanDetector(CallStackDetector):
149 """Detects the start of an address sanitizer callstack.""" 177 """Detects the start of an address sanitizer callstack."""
150 ASAN_CRASH_CALLSTACK_START_REGEX1 = re.compile( 178 ASAN_CRASH_CALLSTACK_START_REGEX1 = re.compile(
151 r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)') 179 r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)')
152 ASAN_CRASH_CALLSTACK_START_REGEX2 = re.compile( 180 ASAN_CRASH_CALLSTACK_START_REGEX2 = re.compile(
153 r'^(READ|WRITE) of size \d+ at|^backtrace:') 181 r'^(READ|WRITE) of size \d+ at|^backtrace:')
154 182
155 ASAN_FREED_CALLSTACK_START_PATTERN = ( 183 ASAN_FREED_CALLSTACK_START_PATTERN = (
156 r'^freed by thread T\d+ (.* )?here:') 184 r'^freed by thread T\d+ (.* )?here:')
157 ASAN_ALLOCATION_CALLSTACK_START_PATTERN = ( 185 ASAN_ALLOCATION_CALLSTACK_START_PATTERN = (
158 r'^(previously )?allocated by thread T\d+ (.* )?here:') 186 r'^(previously )?allocated by thread T\d+ (.* )?here:')
159 ASAN_OTHER_CALLSTACK_START_PATTERN = ( 187 ASAN_OTHER_CALLSTACK_START_PATTERN = (
160 r'^Thread T\d+ (.* )?created by') 188 r'^Thread T\d+ (.* )?created by')
161 189
162 ASAN_NON_CRASH_CALLSTACK_START_PATTERN = re.compile( 190 ASAN_NON_CRASH_CALLSTACK_START_PATTERN = re.compile(
163 '|'.join([ASAN_FREED_CALLSTACK_START_PATTERN, 191 '|'.join([ASAN_FREED_CALLSTACK_START_PATTERN,
164 ASAN_ALLOCATION_CALLSTACK_START_PATTERN, 192 ASAN_ALLOCATION_CALLSTACK_START_PATTERN,
165 ASAN_OTHER_CALLSTACK_START_PATTERN])) 193 ASAN_OTHER_CALLSTACK_START_PATTERN]))
166 194
167 def IsStartOfNewCallStack(self, line, flags=None): 195 def __call__(self, line, flags=None):
168 asan_crash_callstack_start_regex1_match = ( 196 asan_crash_callstack_start_regex1_match = (
169 AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX1.match(line)) 197 AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX1.match(line))
170 if asan_crash_callstack_start_regex1_match: 198 if asan_crash_callstack_start_regex1_match:
171 return (True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, 199 return StartOfCallStack(
172 {'pid': int( 200 0, CallStackFormatType.DEFAULT, LanguageType.CPP,
173 asan_crash_callstack_start_regex1_match.group(1).strip())}) 201 {'pid': int(
202 asan_crash_callstack_start_regex1_match.group(1).strip())})
174 203
175 # Crash stack gets priority 0. 204 # Crash stack gets priority 0.
176 if AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX2.match(line): 205 if AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX2.match(line):
177 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 206 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
207 LanguageType.CPP, {})
178 208
179 # All other callstack gets priority 1. 209 # All other callstack gets priority 1.
180 if AsanDetector.ASAN_NON_CRASH_CALLSTACK_START_PATTERN.match(line): 210 if AsanDetector.ASAN_NON_CRASH_CALLSTACK_START_PATTERN.match(line):
181 return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 211 return StartOfCallStack(1, CallStackFormatType.DEFAULT,
212 LanguageType.CPP, {})
182 213
183 return False, None, None, None, None 214 return None
184 215
185 216
186 class ChromeCrashStackDetector(CallStackDetector): 217 class ChromeCrashStackDetector(CallStackDetector):
187 """Detects the start of an chromecrash(Fracas/Cracas) callstack.""" 218 """Detects the start of an chromecrash(Fracas/Cracas) callstack."""
188 CHROME_CRASH_CALLSTACK_START_REGEX = re.compile(r'CRASHED \[(.*) @ 0x(.*)\]') 219 CHROME_CRASH_CALLSTACK_START_REGEX = re.compile(r'CRASHED \[(.*) @ 0x(.*)\]')
189 JAVA_CALLSTACK_START_REGEX = re.compile(r'\(JAVA\) CRASHED \[(.*) @ 0x(.*)\]') 220 JAVA_CALLSTACK_START_REGEX = re.compile(r'\(JAVA\) CRASHED \[(.*) @ 0x(.*)\]')
190 221
191 def IsStartOfNewCallStack(self, line, flags=None): 222 def __call__(self, line, flags=None):
192 if ChromeCrashStackDetector.CHROME_CRASH_CALLSTACK_START_REGEX.match(line): 223 if ChromeCrashStackDetector.CHROME_CRASH_CALLSTACK_START_REGEX.match(line):
193 # Fracas only provide magic signature stack (crash stack). 224 # Fracas only provide magic signature stack (crash stack).
194 return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {} 225 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
226 LanguageType.CPP, {})
195 227
196 if ChromeCrashStackDetector.JAVA_CALLSTACK_START_REGEX.match(line): 228 if ChromeCrashStackDetector.JAVA_CALLSTACK_START_REGEX.match(line):
197 return True, 0, CallStackFormatType.DEFAULT, LanguageType.JAVA, {} 229 return StartOfCallStack(0, CallStackFormatType.DEFAULT,
230 LanguageType.JAVA, {})
198 231
199 return False, None, None, None, None 232 return None
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/crash/chromecrash_parser.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698