Yavor Goulishev | 9c08e84 | 2020-04-29 14:03:33 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (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 |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "snapshot/win/process_snapshot_win.h" |
| 16 | |
| 17 | #include "base/files/file_path.h" |
| 18 | #include "build/build_config.h" |
| 19 | #include "gtest/gtest.h" |
| 20 | #include "snapshot/win/pe_image_reader.h" |
| 21 | #include "snapshot/win/process_reader_win.h" |
| 22 | #include "test/errors.h" |
| 23 | #include "test/test_paths.h" |
| 24 | #include "test/win/child_launcher.h" |
| 25 | #include "util/file/file_io.h" |
| 26 | #include "util/win/scoped_handle.h" |
| 27 | #include "util/win/scoped_process_suspend.h" |
| 28 | #include "util/win/scoped_set_event.h" |
| 29 | |
| 30 | namespace crashpad { |
| 31 | namespace test { |
| 32 | namespace { |
| 33 | |
| 34 | void TestImageReaderChild(const TestPaths::Architecture architecture) { |
| 35 | UUID done_uuid; |
| 36 | done_uuid.InitializeWithNew(); |
| 37 | ScopedKernelHANDLE done( |
| 38 | CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str())); |
| 39 | ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent"); |
| 40 | |
| 41 | base::FilePath child_test_executable = |
| 42 | TestPaths::BuildArtifact(L"snapshot", |
| 43 | L"image_reader", |
| 44 | TestPaths::FileType::kExecutable, |
| 45 | architecture); |
| 46 | ChildLauncher child(child_test_executable, done_uuid.ToString16()); |
| 47 | ASSERT_NO_FATAL_FAILURE(child.Start()); |
| 48 | |
| 49 | ScopedSetEvent set_done(done.get()); |
| 50 | |
| 51 | char c; |
| 52 | ASSERT_TRUE( |
| 53 | LoggingReadFileExactly(child.stdout_read_handle(), &c, sizeof(c))); |
| 54 | ASSERT_EQ(c, ' '); |
| 55 | |
| 56 | { |
| 57 | ScopedProcessSuspend suspend(child.process_handle()); |
| 58 | |
| 59 | ProcessSnapshotWin process_snapshot; |
| 60 | ASSERT_TRUE(process_snapshot.Initialize( |
| 61 | child.process_handle(), ProcessSuspensionState::kSuspended, 0, 0)); |
| 62 | |
| 63 | ASSERT_GE(process_snapshot.Modules().size(), 2u); |
| 64 | |
| 65 | UUID uuid; |
| 66 | DWORD age; |
| 67 | std::string pdbname; |
| 68 | const std::string suffix(".pdb"); |
| 69 | |
| 70 | // Check the main .exe to see that we can retrieve its sections. |
| 71 | auto module = reinterpret_cast<const internal::ModuleSnapshotWin*>( |
| 72 | process_snapshot.Modules()[0]); |
| 73 | ASSERT_TRUE(module->pe_image_reader().DebugDirectoryInformation( |
| 74 | &uuid, &age, &pdbname)); |
| 75 | EXPECT_NE(pdbname.find("crashpad_snapshot_test_image_reader"), |
| 76 | std::string::npos); |
| 77 | EXPECT_EQ( |
| 78 | pdbname.compare(pdbname.size() - suffix.size(), suffix.size(), suffix), |
| 79 | 0); |
| 80 | |
| 81 | // Check the dll it loads too. |
| 82 | module = reinterpret_cast<const internal::ModuleSnapshotWin*>( |
| 83 | process_snapshot.Modules().back()); |
| 84 | ASSERT_TRUE(module->pe_image_reader().DebugDirectoryInformation( |
| 85 | &uuid, &age, &pdbname)); |
| 86 | EXPECT_NE(pdbname.find("crashpad_snapshot_test_image_reader_module"), |
| 87 | std::string::npos); |
| 88 | EXPECT_EQ( |
| 89 | pdbname.compare(pdbname.size() - suffix.size(), suffix.size(), suffix), |
| 90 | 0); |
| 91 | |
| 92 | // Sum the size of the extra memory in all the threads and confirm it's near |
| 93 | // the limit that the child process set in its CrashpadInfo. |
| 94 | EXPECT_GE(process_snapshot.Threads().size(), 100u); |
| 95 | |
| 96 | size_t extra_memory_total = 0; |
| 97 | for (const auto* thread : process_snapshot.Threads()) { |
| 98 | for (const auto* extra_memory : thread->ExtraMemory()) { |
| 99 | extra_memory_total += extra_memory->Size(); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | // Confirm that less than 1M of extra data was gathered. The cap is set to |
| 104 | // only 100K, but there are other "extra memory" regions that aren't |
| 105 | // included in the cap. (Completely uncapped it would be > 10M.) |
| 106 | EXPECT_LT(extra_memory_total, 1000000u); |
| 107 | } |
| 108 | |
| 109 | // Tell the child it can terminate. |
| 110 | EXPECT_TRUE(set_done.Set()); |
| 111 | |
| 112 | EXPECT_EQ(child.WaitForExit(), 0u); |
| 113 | } |
| 114 | |
| 115 | TEST(ProcessSnapshotTest, CrashpadInfoChild) { |
| 116 | TestImageReaderChild(TestPaths::Architecture::kDefault); |
| 117 | } |
| 118 | |
| 119 | #if defined(ARCH_CPU_64_BITS) |
| 120 | TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) { |
| 121 | if (!TestPaths::Has32BitBuildArtifacts()) { |
| 122 | GTEST_SKIP(); |
| 123 | } |
| 124 | |
| 125 | TestImageReaderChild(TestPaths::Architecture::k32Bit); |
| 126 | } |
| 127 | #endif |
| 128 | |
| 129 | } // namespace |
| 130 | } // namespace test |
| 131 | } // namespace crashpad |