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 "util/mac/process_reader.h" | 15 #include "util/mac/process_reader.h" |
16 | 16 |
17 #include <dispatch/dispatch.h> | 17 #include <dispatch/dispatch.h> |
| 18 #include <mach-o/dyld.h> |
| 19 #include <mach-o/dyld_images.h> |
18 #include <mach/mach.h> | 20 #include <mach/mach.h> |
19 #include <string.h> | 21 #include <string.h> |
| 22 #include <sys/stat.h> |
20 | 23 |
21 #include <map> | 24 #include <map> |
22 #include <string> | 25 #include <string> |
| 26 #include <vector> |
23 | 27 |
24 #include "base/logging.h" | 28 #include "base/logging.h" |
25 #include "base/mac/scoped_mach_port.h" | 29 #include "base/mac/scoped_mach_port.h" |
26 #include "base/posix/eintr_wrapper.h" | 30 #include "base/posix/eintr_wrapper.h" |
| 31 #include "base/strings/stringprintf.h" |
27 #include "build/build_config.h" | 32 #include "build/build_config.h" |
28 #include "gtest/gtest.h" | 33 #include "gtest/gtest.h" |
29 #include "util/file/fd_io.h" | 34 #include "util/file/fd_io.h" |
30 #include "util/stdlib/pointer_container.h" | 35 #include "util/stdlib/pointer_container.h" |
| 36 #include "util/test/errors.h" |
| 37 #include "util/test/mac/dyld.h" |
31 #include "util/test/mac/mach_errors.h" | 38 #include "util/test/mac/mach_errors.h" |
32 #include "util/test/mac/mach_multiprocess.h" | 39 #include "util/test/mac/mach_multiprocess.h" |
33 #include "util/test/errors.h" | |
34 | 40 |
35 namespace { | 41 namespace { |
36 | 42 |
37 using namespace crashpad; | 43 using namespace crashpad; |
38 using namespace crashpad::test; | 44 using namespace crashpad::test; |
39 | 45 |
40 TEST(ProcessReader, SelfBasic) { | 46 TEST(ProcessReader, SelfBasic) { |
41 ProcessReader process_reader; | 47 ProcessReader process_reader; |
42 ASSERT_TRUE(process_reader.Initialize(mach_task_self())); | 48 ASSERT_TRUE(process_reader.Initialize(mach_task_self())); |
43 | 49 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 #else | 83 #else |
78 EXPECT_TRUE(process_reader.Is64Bit()); | 84 EXPECT_TRUE(process_reader.Is64Bit()); |
79 #endif | 85 #endif |
80 | 86 |
81 EXPECT_EQ(getpid(), process_reader.ParentProcessID()); | 87 EXPECT_EQ(getpid(), process_reader.ParentProcessID()); |
82 EXPECT_EQ(ChildPID(), process_reader.ProcessID()); | 88 EXPECT_EQ(ChildPID(), process_reader.ProcessID()); |
83 | 89 |
84 int read_fd = ReadPipeFD(); | 90 int read_fd = ReadPipeFD(); |
85 | 91 |
86 mach_vm_address_t address; | 92 mach_vm_address_t address; |
87 int rv = ReadFD(read_fd, &address, sizeof(address)); | 93 ssize_t rv = ReadFD(read_fd, &address, sizeof(address)); |
88 ASSERT_EQ(static_cast<ssize_t>(sizeof(address)), rv) | 94 ASSERT_EQ(static_cast<ssize_t>(sizeof(address)), rv) |
89 << ErrnoMessage("read"); | 95 << ErrnoMessage("read"); |
90 | 96 |
91 std::string read_string; | 97 std::string read_string; |
92 ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string)); | 98 ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string)); |
93 EXPECT_EQ(kTestMemory, read_string); | 99 EXPECT_EQ(kTestMemory, read_string); |
94 | 100 |
95 // Tell the child that it’s OK to exit. The child needed to be kept alive | 101 // Tell the child that it’s OK to exit. The child needed to be kept alive |
96 // until the parent finished working with it. | 102 // until the parent finished working with it. |
97 int write_fd = WritePipeFD(); | 103 int write_fd = WritePipeFD(); |
98 char c = '\0'; | 104 char c = '\0'; |
99 rv = WriteFD(write_fd, &c, 1); | 105 rv = WriteFD(write_fd, &c, 1); |
100 ASSERT_EQ(1, rv) << ErrnoMessage("write"); | 106 ASSERT_EQ(1, rv) << ErrnoMessage("write"); |
101 } | 107 } |
102 | 108 |
103 void MachMultiprocessChild() override { | 109 void MachMultiprocessChild() override { |
104 int write_fd = WritePipeFD(); | 110 int write_fd = WritePipeFD(); |
105 | 111 |
106 mach_vm_address_t address = | 112 mach_vm_address_t address = |
107 reinterpret_cast<mach_vm_address_t>(kTestMemory); | 113 reinterpret_cast<mach_vm_address_t>(kTestMemory); |
108 int rv = WriteFD(write_fd, &address, sizeof(address)); | 114 ssize_t rv = WriteFD(write_fd, &address, sizeof(address)); |
109 ASSERT_EQ(static_cast<ssize_t>(sizeof(address)), rv) | 115 ASSERT_EQ(static_cast<ssize_t>(sizeof(address)), rv) |
110 << ErrnoMessage("write"); | 116 << ErrnoMessage("write"); |
111 | 117 |
112 // Wait for the parent to say that it’s OK to exit. | 118 // Wait for the parent to say that it’s OK to exit. |
113 int read_fd = ReadPipeFD(); | 119 int read_fd = ReadPipeFD(); |
114 char c; | 120 char c; |
115 rv = ReadFD(read_fd, &c, 1); | 121 rv = ReadFD(read_fd, &c, 1); |
116 ASSERT_EQ(1, rv) << ErrnoMessage("read"); | 122 ASSERT_EQ(1, rv) << ErrnoMessage("read"); |
117 } | 123 } |
118 | 124 |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 int read_fd = ReadPipeFD(); | 447 int read_fd = ReadPipeFD(); |
442 | 448 |
443 // Build a map of all expected threads, keyed by each thread’s ID, and with | 449 // Build a map of all expected threads, keyed by each thread’s ID, and with |
444 // addresses that should lie somewhere within each thread’s stack as values. | 450 // addresses that should lie somewhere within each thread’s stack as values. |
445 // These IDs and addresses all come from the child process via the pipe. | 451 // These IDs and addresses all come from the child process via the pipe. |
446 ThreadMap thread_map; | 452 ThreadMap thread_map; |
447 for (size_t thread_index = 0; | 453 for (size_t thread_index = 0; |
448 thread_index < thread_count_ + 1; | 454 thread_index < thread_count_ + 1; |
449 ++thread_index) { | 455 ++thread_index) { |
450 uint64_t thread_id; | 456 uint64_t thread_id; |
451 int rv = ReadFD(read_fd, &thread_id, sizeof(thread_id)); | 457 ssize_t rv = ReadFD(read_fd, &thread_id, sizeof(thread_id)); |
452 ASSERT_EQ(static_cast<ssize_t>(sizeof(thread_id)), rv) | 458 ASSERT_EQ(static_cast<ssize_t>(sizeof(thread_id)), rv) |
453 << ErrnoMessage("read"); | 459 << ErrnoMessage("read"); |
454 | 460 |
455 TestThreadPool::ThreadExpectation expectation; | 461 TestThreadPool::ThreadExpectation expectation; |
456 rv = ReadFD(read_fd, | 462 rv = ReadFD(read_fd, |
457 &expectation.stack_address, | 463 &expectation.stack_address, |
458 sizeof(expectation.stack_address)); | 464 sizeof(expectation.stack_address)); |
459 ASSERT_EQ(static_cast<ssize_t>(sizeof(expectation.stack_address)), rv) | 465 ASSERT_EQ(static_cast<ssize_t>(sizeof(expectation.stack_address)), rv) |
460 << ErrnoMessage("read"); | 466 << ErrnoMessage("read"); |
461 | 467 |
(...skipping 12 matching lines...) Expand all Loading... |
474 const std::vector<ProcessReaderThread>& threads = process_reader.Threads(); | 480 const std::vector<ProcessReaderThread>& threads = process_reader.Threads(); |
475 | 481 |
476 // The child shouldn’t have any threads other than its main thread and the | 482 // The child shouldn’t have any threads other than its main thread and the |
477 // ones it created in its pool, so pass false for |tolerate_extra_threads|. | 483 // ones it created in its pool, so pass false for |tolerate_extra_threads|. |
478 ExpectSeveralThreads(&thread_map, threads, false); | 484 ExpectSeveralThreads(&thread_map, threads, false); |
479 | 485 |
480 // Tell the child that it’s OK to exit. The child needed to be kept alive | 486 // Tell the child that it’s OK to exit. The child needed to be kept alive |
481 // until the parent finished working with it. | 487 // until the parent finished working with it. |
482 int write_fd = WritePipeFD(); | 488 int write_fd = WritePipeFD(); |
483 char c = '\0'; | 489 char c = '\0'; |
484 int rv = WriteFD(write_fd, &c, 1); | 490 ssize_t rv = WriteFD(write_fd, &c, 1); |
485 ASSERT_EQ(1, rv) << ErrnoMessage("write"); | 491 ASSERT_EQ(1, rv) << ErrnoMessage("write"); |
486 } | 492 } |
487 | 493 |
488 void MachMultiprocessChild() override { | 494 void MachMultiprocessChild() override { |
489 TestThreadPool thread_pool; | 495 TestThreadPool thread_pool; |
490 thread_pool.StartThreads(thread_count_); | 496 thread_pool.StartThreads(thread_count_); |
491 if (testing::Test::HasFatalFailure()) { | 497 if (testing::Test::HasFatalFailure()) { |
492 return; | 498 return; |
493 } | 499 } |
494 | 500 |
495 int write_fd = WritePipeFD(); | 501 int write_fd = WritePipeFD(); |
496 | 502 |
497 // This thread isn’t part of the thread pool, but the parent will be able | 503 // This thread isn’t part of the thread pool, but the parent will be able |
498 // to inspect it. Write an entry for it. | 504 // to inspect it. Write an entry for it. |
499 uint64_t thread_id = PthreadToThreadID(pthread_self()); | 505 uint64_t thread_id = PthreadToThreadID(pthread_self()); |
500 | 506 |
501 int rv = WriteFD(write_fd, &thread_id, sizeof(thread_id)); | 507 ssize_t rv = WriteFD(write_fd, &thread_id, sizeof(thread_id)); |
502 ASSERT_EQ(static_cast<ssize_t>(sizeof(thread_id)), rv) | 508 ASSERT_EQ(static_cast<ssize_t>(sizeof(thread_id)), rv) |
503 << ErrnoMessage("write"); | 509 << ErrnoMessage("write"); |
504 | 510 |
505 TestThreadPool::ThreadExpectation expectation; | 511 TestThreadPool::ThreadExpectation expectation; |
506 expectation.stack_address = reinterpret_cast<mach_vm_address_t>(&thread_id); | 512 expectation.stack_address = reinterpret_cast<mach_vm_address_t>(&thread_id); |
507 expectation.suspend_count = 0; | 513 expectation.suspend_count = 0; |
508 | 514 |
509 rv = WriteFD(write_fd, | 515 rv = WriteFD(write_fd, |
510 &expectation.stack_address, | 516 &expectation.stack_address, |
511 sizeof(expectation.stack_address)); | 517 sizeof(expectation.stack_address)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); | 566 ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); |
561 process_reader_threaded_child.Run(); | 567 process_reader_threaded_child.Run(); |
562 } | 568 } |
563 | 569 |
564 TEST(ProcessReader, ChildSeveralThreads) { | 570 TEST(ProcessReader, ChildSeveralThreads) { |
565 const size_t kChildThreads = 64; | 571 const size_t kChildThreads = 64; |
566 ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); | 572 ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); |
567 process_reader_threaded_child.Run(); | 573 process_reader_threaded_child.Run(); |
568 } | 574 } |
569 | 575 |
| 576 TEST(ProcessReader, SelfModules) { |
| 577 ProcessReader process_reader; |
| 578 ASSERT_TRUE(process_reader.Initialize(mach_task_self())); |
| 579 |
| 580 uint32_t dyld_image_count = _dyld_image_count(); |
| 581 const std::vector<ProcessReaderModule>& modules = process_reader.Modules(); |
| 582 |
| 583 // There needs to be at least an entry for the main executable, for a dylib, |
| 584 // and for dyld. |
| 585 ASSERT_GE(modules.size(), 3u); |
| 586 |
| 587 // dyld_image_count doesn’t include an entry for dyld itself, but |modules| |
| 588 // does. |
| 589 ASSERT_EQ(dyld_image_count + 1, modules.size()); |
| 590 |
| 591 for (uint32_t index = 0; index < dyld_image_count; ++index) { |
| 592 SCOPED_TRACE(base::StringPrintf( |
| 593 "index %u, name %s", index, modules[index].name.c_str())); |
| 594 |
| 595 const char* dyld_image_name = _dyld_get_image_name(index); |
| 596 EXPECT_EQ(dyld_image_name, modules[index].name); |
| 597 EXPECT_EQ( |
| 598 reinterpret_cast<mach_vm_address_t>(_dyld_get_image_header(index)), |
| 599 modules[index].address); |
| 600 |
| 601 if (index == 0) { |
| 602 // dyld didn’t load the main executable, so it couldn’t record its |
| 603 // timestamp, and it is reported as 0. |
| 604 EXPECT_EQ(0, modules[index].timestamp); |
| 605 } else { |
| 606 // Hope that the module didn’t change on disk. |
| 607 struct stat stat_buf; |
| 608 int rv = stat(dyld_image_name, &stat_buf); |
| 609 EXPECT_EQ(0, rv) << ErrnoMessage("stat"); |
| 610 if (rv == 0) { |
| 611 EXPECT_EQ(stat_buf.st_mtime, modules[index].timestamp); |
| 612 } |
| 613 } |
| 614 } |
| 615 |
| 616 size_t index = modules.size() - 1; |
| 617 EXPECT_EQ("/usr/lib/dyld", modules[index].name); |
| 618 |
| 619 // dyld didn’t load itself either, so it couldn’t record its timestamp, and it |
| 620 // is also reported as 0. |
| 621 EXPECT_EQ(0, modules[index].timestamp); |
| 622 |
| 623 const struct dyld_all_image_infos* dyld_image_infos = |
| 624 _dyld_get_all_image_infos(); |
| 625 if (dyld_image_infos->version >= 2) { |
| 626 EXPECT_EQ(reinterpret_cast<mach_vm_address_t>( |
| 627 dyld_image_infos->dyldImageLoadAddress), modules[index].address); |
| 628 } |
| 629 } |
| 630 |
| 631 class ProcessReaderModulesChild final : public MachMultiprocess { |
| 632 public: |
| 633 ProcessReaderModulesChild() : MachMultiprocess() {} |
| 634 |
| 635 ~ProcessReaderModulesChild() {} |
| 636 |
| 637 private: |
| 638 void MachMultiprocessParent() override { |
| 639 ProcessReader process_reader; |
| 640 ASSERT_TRUE(process_reader.Initialize(ChildTask())); |
| 641 |
| 642 const std::vector<ProcessReaderModule>& modules = process_reader.Modules(); |
| 643 |
| 644 // There needs to be at least an entry for the main executable, for a dylib, |
| 645 // and for dyld. |
| 646 ASSERT_GE(modules.size(), 3u); |
| 647 |
| 648 int read_fd = ReadPipeFD(); |
| 649 |
| 650 uint32_t expect_modules; |
| 651 ssize_t rv = ReadFD(read_fd, &expect_modules, sizeof(expect_modules)); |
| 652 ASSERT_EQ(static_cast<ssize_t>(sizeof(expect_modules)), rv) |
| 653 << ErrnoMessage("read"); |
| 654 |
| 655 ASSERT_EQ(expect_modules, modules.size()); |
| 656 |
| 657 for (size_t index = 0; index < modules.size(); ++index) { |
| 658 SCOPED_TRACE(base::StringPrintf( |
| 659 "index %zu, name %s", index, modules[index].name.c_str())); |
| 660 |
| 661 uint32_t expect_name_length; |
| 662 rv = ReadFD( |
| 663 read_fd, &expect_name_length, sizeof(expect_name_length)); |
| 664 ASSERT_EQ(static_cast<ssize_t>(sizeof(expect_name_length)), rv) |
| 665 << ErrnoMessage("read"); |
| 666 |
| 667 // The NUL terminator is not read. |
| 668 std::string expect_name(expect_name_length, '\0'); |
| 669 rv = ReadFD(read_fd, &expect_name[0], expect_name_length); |
| 670 ASSERT_EQ(static_cast<ssize_t>(expect_name_length), rv) |
| 671 << ErrnoMessage("read"); |
| 672 |
| 673 EXPECT_EQ(expect_name, modules[index].name); |
| 674 |
| 675 mach_vm_address_t expect_address; |
| 676 rv = ReadFD(read_fd, &expect_address, sizeof(expect_address)); |
| 677 ASSERT_EQ(static_cast<ssize_t>(sizeof(expect_address)), rv) |
| 678 << ErrnoMessage("read"); |
| 679 |
| 680 EXPECT_EQ(expect_address, modules[index].address); |
| 681 |
| 682 if (index == 0 || index == modules.size() - 1) { |
| 683 // dyld didn’t load the main executable or itself, so it couldn’t record |
| 684 // these timestamps, and they are reported as 0. |
| 685 EXPECT_EQ(0, modules[index].timestamp); |
| 686 } else { |
| 687 // Hope that the module didn’t change on disk. |
| 688 struct stat stat_buf; |
| 689 int rv = stat(expect_name.c_str(), &stat_buf); |
| 690 EXPECT_EQ(0, rv) << ErrnoMessage("stat"); |
| 691 if (rv == 0) { |
| 692 EXPECT_EQ(stat_buf.st_mtime, modules[index].timestamp); |
| 693 } |
| 694 } |
| 695 } |
| 696 |
| 697 // Tell the child that it’s OK to exit. The child needed to be kept alive |
| 698 // until the parent finished working with it. |
| 699 int write_fd = WritePipeFD(); |
| 700 char c = '\0'; |
| 701 rv = WriteFD(write_fd, &c, 1); |
| 702 ASSERT_EQ(1, rv) << ErrnoMessage("write"); |
| 703 } |
| 704 |
| 705 void MachMultiprocessChild() override { |
| 706 int write_fd = WritePipeFD(); |
| 707 |
| 708 uint32_t dyld_image_count = _dyld_image_count(); |
| 709 const struct dyld_all_image_infos* dyld_image_infos = |
| 710 _dyld_get_all_image_infos(); |
| 711 |
| 712 uint32_t write_image_count = dyld_image_count; |
| 713 if (dyld_image_infos->version >= 2) { |
| 714 // dyld_image_count doesn’t include an entry for dyld itself, but one will |
| 715 // be written. |
| 716 ++write_image_count; |
| 717 } |
| 718 |
| 719 ssize_t rv = WriteFD( |
| 720 write_fd, &write_image_count, sizeof(write_image_count)); |
| 721 ASSERT_EQ(static_cast<ssize_t>(sizeof(write_image_count)), rv) |
| 722 << ErrnoMessage("write"); |
| 723 |
| 724 for (size_t index = 0; index < write_image_count; ++index) { |
| 725 const char* dyld_image_name; |
| 726 mach_vm_address_t dyld_image_address; |
| 727 |
| 728 if (index < dyld_image_count) { |
| 729 dyld_image_name = _dyld_get_image_name(index); |
| 730 dyld_image_address = |
| 731 reinterpret_cast<mach_vm_address_t>(_dyld_get_image_header(index)); |
| 732 } else { |
| 733 dyld_image_name = "/usr/lib/dyld"; |
| 734 dyld_image_address = reinterpret_cast<mach_vm_address_t>( |
| 735 dyld_image_infos->dyldImageLoadAddress); |
| 736 } |
| 737 |
| 738 uint32_t dyld_image_name_length = strlen(dyld_image_name); |
| 739 rv = WriteFD( |
| 740 write_fd, &dyld_image_name_length, sizeof(dyld_image_name_length)); |
| 741 ASSERT_EQ(static_cast<ssize_t>(sizeof(dyld_image_name_length)), rv) |
| 742 << ErrnoMessage("write"); |
| 743 |
| 744 // The NUL terminator is not written. |
| 745 rv = WriteFD(write_fd, dyld_image_name, dyld_image_name_length); |
| 746 ASSERT_EQ(static_cast<ssize_t>(dyld_image_name_length), rv) |
| 747 << ErrnoMessage("write"); |
| 748 |
| 749 rv = WriteFD(write_fd, &dyld_image_address, sizeof(dyld_image_address)); |
| 750 ASSERT_EQ(static_cast<ssize_t>(sizeof(dyld_image_address)), rv) |
| 751 << ErrnoMessage("write"); |
| 752 } |
| 753 |
| 754 // Wait for the parent to say that it’s OK to exit. |
| 755 int read_fd = ReadPipeFD(); |
| 756 char c; |
| 757 rv = ReadFD(read_fd, &c, 1); |
| 758 ASSERT_EQ(1, rv) << ErrnoMessage("read"); |
| 759 } |
| 760 |
| 761 DISALLOW_COPY_AND_ASSIGN(ProcessReaderModulesChild); |
| 762 }; |
| 763 |
| 764 TEST(ProcessReader, ChildModules) { |
| 765 ProcessReaderModulesChild process_reader_modules_child; |
| 766 process_reader_modules_child.Run(); |
| 767 } |
| 768 |
570 } // namespace | 769 } // namespace |
OLD | NEW |