OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright 2015 The Crashpad Authors. All rights reserved. | 3 # Copyright 2015 The Crashpad Authors. All rights reserved. |
4 # | 4 # |
5 # Licensed under the Apache License, Version 2.0 (the "License"); | 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
6 # you may not use this file except in compliance with the License. | 6 # you may not use this file except in compliance with the License. |
7 # You may obtain a copy of the License at | 7 # You may obtain a copy of the License at |
8 # | 8 # |
9 # http://www.apache.org/licenses/LICENSE-2.0 | 9 # http://www.apache.org/licenses/LICENSE-2.0 |
10 # | 10 # |
11 # Unless required by applicable law or agreed to in writing, software | 11 # Unless required by applicable law or agreed to in writing, software |
12 # distributed under the License is distributed on an "AS IS" BASIS, | 12 # distributed under the License is distributed on an "AS IS" BASIS, |
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 # See the License for the specific language governing permissions and | 14 # See the License for the specific language governing permissions and |
15 # limitations under the License. | 15 # limitations under the License. |
16 | 16 |
17 import os | 17 import os |
18 import platform | 18 import platform |
19 import random | 19 import random |
20 import re | 20 import re |
21 import subprocess | 21 import subprocess |
22 import sys | 22 import sys |
23 import tempfile | 23 import tempfile |
24 import time | 24 import time |
25 | 25 |
26 | 26 |
27 g_temp_dirs = [] | 27 g_temp_dirs = [] |
| 28 g_had_failures = False |
28 | 29 |
29 | 30 |
30 def MakeTempDir(): | 31 def MakeTempDir(): |
31 global g_temp_dirs | 32 global g_temp_dirs |
32 new_dir = tempfile.mkdtemp() | 33 new_dir = tempfile.mkdtemp() |
33 g_temp_dirs.append(new_dir) | 34 g_temp_dirs.append(new_dir) |
34 return new_dir | 35 return new_dir |
35 | 36 |
36 | 37 |
37 def CleanUpTempDirs(): | 38 def CleanUpTempDirs(): |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 sys.stdout.flush() | 175 sys.stdout.flush() |
175 else: | 176 else: |
176 print >>sys.stderr, '-' * 80 | 177 print >>sys.stderr, '-' * 80 |
177 print >>sys.stderr, 'FAILED - %s' % message | 178 print >>sys.stderr, 'FAILED - %s' % message |
178 print >>sys.stderr, '-' * 80 | 179 print >>sys.stderr, '-' * 80 |
179 print >>sys.stderr, 'did not match:\n %s' % pattern | 180 print >>sys.stderr, 'did not match:\n %s' % pattern |
180 print >>sys.stderr, '-' * 80 | 181 print >>sys.stderr, '-' * 80 |
181 print >>sys.stderr, 'remaining output was:\n %s' % self.out | 182 print >>sys.stderr, 'remaining output was:\n %s' % self.out |
182 print >>sys.stderr, '-' * 80 | 183 print >>sys.stderr, '-' * 80 |
183 sys.stderr.flush() | 184 sys.stderr.flush() |
184 sys.exit(1) | 185 global g_had_failures |
| 186 g_had_failures = True |
| 187 |
| 188 def Find(self, pattern, re_flags=0): |
| 189 match_obj = re.search(pattern, self.out, re_flags) |
| 190 if match_obj: |
| 191 # Matched. Consume up to end of match. |
| 192 self.out = self.out[match_obj.end(0):] |
| 193 return match_obj |
| 194 return None |
185 | 195 |
186 | 196 |
187 def RunTests(cdb_path, | 197 def RunTests(cdb_path, |
188 dump_path, | 198 dump_path, |
189 start_handler_dump_path, | 199 start_handler_dump_path, |
190 destroyed_dump_path, | 200 destroyed_dump_path, |
191 z7_dump_path, | 201 z7_dump_path, |
192 other_program_path, | 202 other_program_path, |
193 other_program_no_exception_path, | 203 other_program_no_exception_path, |
194 pipe_name): | 204 pipe_name): |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 out.Check(r'ntdll\.dll', 'ntdll present', re.IGNORECASE) | 268 out.Check(r'ntdll\.dll', 'ntdll present', re.IGNORECASE) |
259 | 269 |
260 # Check that there is no stack trace in the self-destroyed process. Confirm | 270 # Check that there is no stack trace in the self-destroyed process. Confirm |
261 # that the top is where we expect it (that's based only on IP), but subsequent | 271 # that the top is where we expect it (that's based only on IP), but subsequent |
262 # stack entries will not be available. This confirms that we have a mostly | 272 # stack entries will not be available. This confirms that we have a mostly |
263 # valid dump, but that the stack was omitted. | 273 # valid dump, but that the stack was omitted. |
264 out.Check(r'self_destroying_program!crashpad::`anonymous namespace\'::' | 274 out.Check(r'self_destroying_program!crashpad::`anonymous namespace\'::' |
265 r'FreeOwnStackAndBreak.*\nquit:', | 275 r'FreeOwnStackAndBreak.*\nquit:', |
266 'at correct location, no additional stack entries') | 276 'at correct location, no additional stack entries') |
267 | 277 |
268 # Switch to the other thread after jumping to the exception, and examine | 278 # Dump memory pointed to be EDI on the background suspended thread. We don't |
269 # memory. | 279 # know the index of the thread because the system may have started other |
270 out = CdbRun(cdb_path, dump_path, '.ecxr; ~1s; db /c14 edi') | 280 # threads, so first do a run to extract the thread index that's suspended, and |
| 281 # then another run to dump the data pointed to by EDI for that thread. |
| 282 out = CdbRun(cdb_path, dump_path, '.ecxr;~') |
| 283 match_obj = out.Find(r'(\d+)\s+Id: [0-9a-f.]+ Suspend: 1 Teb:') |
| 284 if match_obj: |
| 285 thread = match_obj.group(1) |
| 286 out = CdbRun(cdb_path, dump_path, '.ecxr;~' + thread + 's;db /c14 edi') |
271 out.Check(r'63 62 61 60 5f 5e 5d 5c-5b 5a 59 58 57 56 55 54 53 52 51 50', | 287 out.Check(r'63 62 61 60 5f 5e 5d 5c-5b 5a 59 58 57 56 55 54 53 52 51 50', |
272 'data pointed to by registers captured') | 288 'data pointed to by registers captured') |
273 | 289 |
274 # Move up one stack frame after jumping to the exception, and examine memory. | 290 # Move up one stack frame after jumping to the exception, and examine memory. |
275 out = CdbRun(cdb_path, dump_path, | 291 out = CdbRun(cdb_path, dump_path, |
276 '.ecxr; .f+; dd /c100 poi(offset_pointer)-20') | 292 '.ecxr; .f+; dd /c100 poi(offset_pointer)-20') |
277 out.Check(r'80000078 00000079 8000007a 0000007b 8000007c 0000007d 8000007e ' | 293 out.Check(r'80000078 00000079 8000007a 0000007b 8000007c 0000007d 8000007e ' |
278 r'0000007f 80000080 00000081 80000082 00000083 80000084 00000085 ' | 294 r'0000007f 80000080 00000081 80000082 00000083 80000084 00000085 ' |
279 r'80000086 00000087 80000088 00000089 8000008a 0000008b 8000008c ' | 295 r'80000086 00000087 80000088 00000089 8000008a 0000008b 8000008c ' |
280 r'0000008d 8000008e 0000008f 80000090 00000091 80000092 00000093 ' | 296 r'0000008d 8000008e 0000008f 80000090 00000091 80000092 00000093 ' |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 out.Check(r'z7_test(!CrashMe\+0xe|\+0x100e):', | 337 out.Check(r'z7_test(!CrashMe\+0xe|\+0x100e):', |
322 'exception in z7 at correct location') | 338 'exception in z7 at correct location') |
323 out.Check(r'z7_test C \(codeview symbols\) z7_test.dll', | 339 out.Check(r'z7_test C \(codeview symbols\) z7_test.dll', |
324 'expected non-pdb symbol format') | 340 'expected non-pdb symbol format') |
325 | 341 |
326 out = CdbRun(cdb_path, other_program_path, '.ecxr;k;~') | 342 out = CdbRun(cdb_path, other_program_path, '.ecxr;k;~') |
327 out.Check('Unknown exception - code deadbea7', | 343 out.Check('Unknown exception - code deadbea7', |
328 'other program dump exception code') | 344 'other program dump exception code') |
329 out.Check('!Sleep', 'other program reasonable location') | 345 out.Check('!Sleep', 'other program reasonable location') |
330 out.Check('hanging_program!Thread1', 'other program dump right thread') | 346 out.Check('hanging_program!Thread1', 'other program dump right thread') |
331 out.Check('\. 1 Id.*Suspend: 0 ', | 347 count = 0 |
332 'other program exception on correct thread and correct suspend') | 348 while True: |
333 out.Check(' 4 Id.*Suspend: 0 ', | 349 match_obj = out.Find(r'Id.*Suspend: (\d+) ') |
334 'other program injection thread correct suspend') | 350 if match_obj: |
| 351 if match_obj.group(1) != '0': |
| 352 out.Check(r'FAILED', 'all suspend counts should be 0') |
| 353 else: |
| 354 count += 1 |
| 355 else: |
| 356 break |
| 357 assert count > 2 |
335 | 358 |
336 out = CdbRun(cdb_path, other_program_no_exception_path, '.ecxr;k') | 359 out = CdbRun(cdb_path, other_program_no_exception_path, '.ecxr;k') |
337 out.Check('Unknown exception - code 0cca11ed', | 360 out.Check('Unknown exception - code 0cca11ed', |
338 'other program with no exception given') | 361 'other program with no exception given') |
339 out.Check('!RaiseException', 'other program in RaiseException()') | 362 out.Check('!RaiseException', 'other program in RaiseException()') |
340 | 363 |
341 | 364 |
342 def main(args): | 365 def main(args): |
343 try: | 366 try: |
344 if len(args) != 1: | 367 if len(args) != 1: |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 | 413 |
391 RunTests(cdb_path, | 414 RunTests(cdb_path, |
392 crashy_dump_path, | 415 crashy_dump_path, |
393 start_handler_dump_path, | 416 start_handler_dump_path, |
394 destroyed_dump_path, | 417 destroyed_dump_path, |
395 z7_dump_path, | 418 z7_dump_path, |
396 other_program_path, | 419 other_program_path, |
397 other_program_no_exception_path, | 420 other_program_no_exception_path, |
398 pipe_name) | 421 pipe_name) |
399 | 422 |
400 return 0 | 423 return 1 if g_had_failures else 0 |
401 finally: | 424 finally: |
402 CleanUpTempDirs() | 425 CleanUpTempDirs() |
403 | 426 |
404 | 427 |
405 if __name__ == '__main__': | 428 if __name__ == '__main__': |
406 sys.exit(main(sys.argv[1:])) | 429 sys.exit(main(sys.argv[1:])) |
OLD | NEW |