OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "minidump/minidump_thread_writer.h" | 15 #include "minidump/minidump_thread_writer.h" |
16 | 16 |
17 #include <dbghelp.h> | 17 #include <dbghelp.h> |
18 #include <sys/types.h> | 18 #include <sys/types.h> |
19 | 19 |
| 20 #include "base/strings/stringprintf.h" |
20 #include "gtest/gtest.h" | 21 #include "gtest/gtest.h" |
21 #include "minidump/minidump_context_writer.h" | 22 #include "minidump/minidump_context_writer.h" |
22 #include "minidump/minidump_memory_writer.h" | 23 #include "minidump/minidump_memory_writer.h" |
23 #include "minidump/minidump_file_writer.h" | 24 #include "minidump/minidump_file_writer.h" |
| 25 #include "minidump/minidump_thread_id_map.h" |
24 #include "minidump/test/minidump_context_test_util.h" | 26 #include "minidump/test/minidump_context_test_util.h" |
25 #include "minidump/test/minidump_memory_writer_test_util.h" | 27 #include "minidump/test/minidump_memory_writer_test_util.h" |
26 #include "minidump/test/minidump_file_writer_test_util.h" | 28 #include "minidump/test/minidump_file_writer_test_util.h" |
27 #include "minidump/test/minidump_writable_test_util.h" | 29 #include "minidump/test/minidump_writable_test_util.h" |
| 30 #include "snapshot/test/test_cpu_context.h" |
| 31 #include "snapshot/test/test_memory_snapshot.h" |
| 32 #include "snapshot/test/test_thread_snapshot.h" |
28 #include "util/file/string_file_writer.h" | 33 #include "util/file/string_file_writer.h" |
29 | 34 |
30 namespace crashpad { | 35 namespace crashpad { |
31 namespace test { | 36 namespace test { |
32 namespace { | 37 namespace { |
33 | 38 |
34 // This returns the MINIDUMP_THREAD_LIST stream in |thread_list|. If | 39 // This returns the MINIDUMP_THREAD_LIST stream in |thread_list|. If |
35 // |memory_list| is not nullptr, a MINIDUMP_MEMORY_LIST stream is also expected | 40 // |memory_list| is not nullptr, a MINIDUMP_MEMORY_LIST stream is also expected |
36 // in |file_contents|, and that stream will be returned in |memory_list|. | 41 // in |file_contents|, and that stream will be returned in |memory_list|. |
37 void GetThreadListStream(const std::string& file_contents, | 42 void GetThreadListStream(const std::string& file_contents, |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 file_writer.string(), | 473 file_writer.string(), |
469 kMemoryValue2, | 474 kMemoryValue2, |
470 true)); | 475 true)); |
471 ASSERT_NO_FATAL_FAILURE( | 476 ASSERT_NO_FATAL_FAILURE( |
472 ExpectMinidumpContextX86(kSeed2, observed_context, false)); | 477 ExpectMinidumpContextX86(kSeed2, observed_context, false)); |
473 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor( | 478 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor( |
474 observed_stack, &memory_list->MemoryRanges[2])); | 479 observed_stack, &memory_list->MemoryRanges[2])); |
475 } | 480 } |
476 } | 481 } |
477 | 482 |
| 483 struct InitializeFromSnapshotX86Traits { |
| 484 typedef MinidumpContextX86 MinidumpContextType; |
| 485 static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
| 486 return InitializeCPUContextX86(context, seed); |
| 487 } |
| 488 static void ExpectMinidumpContext( |
| 489 uint32_t expect_seed, const MinidumpContextX86* observed, bool snapshot) { |
| 490 return ExpectMinidumpContextX86(expect_seed, observed, snapshot); |
| 491 } |
| 492 }; |
| 493 |
| 494 struct InitializeFromSnapshotAMD64Traits { |
| 495 typedef MinidumpContextAMD64 MinidumpContextType; |
| 496 static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
| 497 return InitializeCPUContextX86_64(context, seed); |
| 498 } |
| 499 static void ExpectMinidumpContext(uint32_t expect_seed, |
| 500 const MinidumpContextAMD64* observed, |
| 501 bool snapshot) { |
| 502 return ExpectMinidumpContextAMD64(expect_seed, observed, snapshot); |
| 503 } |
| 504 }; |
| 505 |
| 506 struct InitializeFromSnapshotNoContextTraits { |
| 507 typedef MinidumpContextX86 MinidumpContextType; |
| 508 static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
| 509 context->architecture = kCPUArchitectureUnknown; |
| 510 } |
| 511 static void ExpectMinidumpContext(uint32_t expect_seed, |
| 512 const MinidumpContextX86* observed, |
| 513 bool snapshot) { |
| 514 FAIL(); |
| 515 } |
| 516 }; |
| 517 |
| 518 template <typename Traits> |
| 519 void RunInitializeFromSnapshotTest(bool thread_id_collision) { |
| 520 typedef typename Traits::MinidumpContextType MinidumpContextType; |
| 521 MINIDUMP_THREAD expect_threads[3] = {}; |
| 522 uint64_t thread_ids[arraysize(expect_threads)] = {}; |
| 523 uint8_t memory_values[arraysize(expect_threads)] = {}; |
| 524 uint32_t context_seeds[arraysize(expect_threads)] = {}; |
| 525 |
| 526 expect_threads[0].ThreadId = 1; |
| 527 expect_threads[0].SuspendCount = 2; |
| 528 expect_threads[0].Priority = 3; |
| 529 expect_threads[0].Teb = 0x0123456789abcdef; |
| 530 expect_threads[0].Stack.StartOfMemoryRange = 0x1000; |
| 531 expect_threads[0].Stack.Memory.DataSize = 0x100; |
| 532 expect_threads[0].ThreadContext.DataSize = sizeof(MinidumpContextType); |
| 533 memory_values[0] = 'A'; |
| 534 context_seeds[0] = 0x80000000; |
| 535 |
| 536 // The thread at index 1 has no stack. |
| 537 expect_threads[1].ThreadId = 11; |
| 538 expect_threads[1].SuspendCount = 12; |
| 539 expect_threads[1].Priority = 13; |
| 540 expect_threads[1].Teb = 0xfedcba9876543210; |
| 541 expect_threads[1].ThreadContext.DataSize = sizeof(MinidumpContextType); |
| 542 context_seeds[1] = 0x40000001; |
| 543 |
| 544 expect_threads[2].ThreadId = 21; |
| 545 expect_threads[2].SuspendCount = 22; |
| 546 expect_threads[2].Priority = 23; |
| 547 expect_threads[2].Teb = 0x1111111111111111; |
| 548 expect_threads[2].Stack.StartOfMemoryRange = 0x3000; |
| 549 expect_threads[2].Stack.Memory.DataSize = 0x300; |
| 550 expect_threads[2].ThreadContext.DataSize = sizeof(MinidumpContextType); |
| 551 memory_values[2] = 'd'; |
| 552 context_seeds[2] = 0x20000002; |
| 553 |
| 554 if (thread_id_collision) { |
| 555 thread_ids[0] = 0x0123456700000001; |
| 556 thread_ids[1] = 0x89abcdef00000001; |
| 557 thread_ids[2] = 4; |
| 558 expect_threads[0].ThreadId = 0; |
| 559 expect_threads[1].ThreadId = 1; |
| 560 expect_threads[2].ThreadId = 2; |
| 561 } else { |
| 562 thread_ids[0] = 1; |
| 563 thread_ids[1] = 11; |
| 564 thread_ids[2] = 22; |
| 565 expect_threads[0].ThreadId = thread_ids[0]; |
| 566 expect_threads[1].ThreadId = thread_ids[1]; |
| 567 expect_threads[2].ThreadId = thread_ids[2]; |
| 568 } |
| 569 |
| 570 PointerVector<TestThreadSnapshot> thread_snapshots_owner; |
| 571 std::vector<const ThreadSnapshot*> thread_snapshots; |
| 572 for (size_t index = 0; index < arraysize(expect_threads); ++index) { |
| 573 TestThreadSnapshot* thread_snapshot = new TestThreadSnapshot(); |
| 574 thread_snapshots_owner.push_back(thread_snapshot); |
| 575 |
| 576 thread_snapshot->SetThreadID(thread_ids[index]); |
| 577 thread_snapshot->SetSuspendCount(expect_threads[index].SuspendCount); |
| 578 thread_snapshot->SetPriority(expect_threads[index].Priority); |
| 579 thread_snapshot->SetThreadSpecificDataAddress(expect_threads[index].Teb); |
| 580 |
| 581 if (expect_threads[index].Stack.Memory.DataSize) { |
| 582 auto memory_snapshot = make_scoped_ptr(new TestMemorySnapshot()); |
| 583 memory_snapshot->SetAddress( |
| 584 expect_threads[index].Stack.StartOfMemoryRange); |
| 585 memory_snapshot->SetSize(expect_threads[index].Stack.Memory.DataSize); |
| 586 memory_snapshot->SetValue(memory_values[index]); |
| 587 thread_snapshot->SetStack(memory_snapshot.Pass()); |
| 588 } |
| 589 |
| 590 Traits::InitializeCPUContext(thread_snapshot->MutableContext(), |
| 591 context_seeds[index]); |
| 592 |
| 593 thread_snapshots.push_back(thread_snapshot); |
| 594 } |
| 595 |
| 596 auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter()); |
| 597 auto memory_list_writer = make_scoped_ptr(new MinidumpMemoryListWriter()); |
| 598 thread_list_writer->SetMemoryListWriter(memory_list_writer.get()); |
| 599 MinidumpThreadIDMap thread_id_map; |
| 600 thread_list_writer->InitializeFromSnapshot(thread_snapshots, &thread_id_map); |
| 601 |
| 602 MinidumpFileWriter minidump_file_writer; |
| 603 minidump_file_writer.AddStream(thread_list_writer.Pass()); |
| 604 minidump_file_writer.AddStream(memory_list_writer.Pass()); |
| 605 |
| 606 StringFileWriter file_writer; |
| 607 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
| 608 |
| 609 const MINIDUMP_THREAD_LIST* thread_list; |
| 610 const MINIDUMP_MEMORY_LIST* memory_list; |
| 611 ASSERT_NO_FATAL_FAILURE( |
| 612 GetThreadListStream(file_writer.string(), &thread_list, &memory_list)); |
| 613 |
| 614 ASSERT_EQ(3u, thread_list->NumberOfThreads); |
| 615 ASSERT_EQ(2u, memory_list->NumberOfMemoryRanges); |
| 616 |
| 617 size_t memory_index = 0; |
| 618 for (size_t index = 0; index < thread_list->NumberOfThreads; ++index) { |
| 619 SCOPED_TRACE(base::StringPrintf("index %zu", index)); |
| 620 |
| 621 const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
| 622 const MINIDUMP_MEMORY_DESCRIPTOR** observed_stack_p = |
| 623 expect_threads[index].Stack.Memory.DataSize ? &observed_stack : nullptr; |
| 624 const MinidumpContextType* observed_context; |
| 625 ASSERT_NO_FATAL_FAILURE( |
| 626 ExpectThread(&expect_threads[index], |
| 627 &thread_list->Threads[index], |
| 628 file_writer.string(), |
| 629 observed_stack_p, |
| 630 reinterpret_cast<const void**>(&observed_context))); |
| 631 |
| 632 ASSERT_NO_FATAL_FAILURE(Traits::ExpectMinidumpContext( |
| 633 context_seeds[index], observed_context, true)); |
| 634 |
| 635 if (observed_stack_p) { |
| 636 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptorAndContents( |
| 637 &expect_threads[index].Stack, |
| 638 observed_stack, |
| 639 file_writer.string(), |
| 640 memory_values[index], |
| 641 index == thread_list->NumberOfThreads - 1)); |
| 642 |
| 643 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor( |
| 644 observed_stack, &memory_list->MemoryRanges[memory_index])); |
| 645 |
| 646 ++memory_index; |
| 647 } |
| 648 } |
| 649 } |
| 650 |
| 651 TEST(MinidumpThreadWriter, InitializeFromSnapshot_x86) { |
| 652 RunInitializeFromSnapshotTest<InitializeFromSnapshotX86Traits>(false); |
| 653 } |
| 654 |
| 655 TEST(MinidumpThreadWriter, InitializeFromSnapshot_AMD64) { |
| 656 RunInitializeFromSnapshotTest<InitializeFromSnapshotAMD64Traits>(false); |
| 657 } |
| 658 |
| 659 TEST(MinidumpThreadWriter, InitializeFromSnapshot_ThreadIDCollision) { |
| 660 RunInitializeFromSnapshotTest<InitializeFromSnapshotX86Traits>(true); |
| 661 } |
| 662 |
478 TEST(MinidumpThreadWriterDeathTest, NoContext) { | 663 TEST(MinidumpThreadWriterDeathTest, NoContext) { |
479 MinidumpFileWriter minidump_file_writer; | 664 MinidumpFileWriter minidump_file_writer; |
480 auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter()); | 665 auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter()); |
481 | 666 |
482 auto thread_writer = make_scoped_ptr(new MinidumpThreadWriter()); | 667 auto thread_writer = make_scoped_ptr(new MinidumpThreadWriter()); |
483 | 668 |
484 thread_list_writer->AddThread(thread_writer.Pass()); | 669 thread_list_writer->AddThread(thread_writer.Pass()); |
485 minidump_file_writer.AddStream(thread_list_writer.Pass()); | 670 minidump_file_writer.AddStream(thread_list_writer.Pass()); |
486 | 671 |
487 StringFileWriter file_writer; | 672 StringFileWriter file_writer; |
488 ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "context_"); | 673 ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "context_"); |
489 } | 674 } |
490 | 675 |
| 676 TEST(MinidumpThreadWriterDeathTest, InitializeFromSnapshot_NoContext) { |
| 677 ASSERT_DEATH( |
| 678 RunInitializeFromSnapshotTest<InitializeFromSnapshotNoContextTraits>( |
| 679 false), "context_"); |
| 680 } |
| 681 |
491 } // namespace | 682 } // namespace |
492 } // namespace test | 683 } // namespace test |
493 } // namespace crashpad | 684 } // namespace crashpad |
OLD | NEW |