| OLD | NEW |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 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, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #include "util/thread/thread.h" | 29 #include "util/thread/thread.h" |
| 30 #include "util/win/exception_handler_server.h" | 30 #include "util/win/exception_handler_server.h" |
| 31 #include "util/win/registration_protocol_win.h" | 31 #include "util/win/registration_protocol_win.h" |
| 32 #include "util/win/scoped_handle.h" | 32 #include "util/win/scoped_handle.h" |
| 33 #include "util/win/scoped_process_suspend.h" | 33 #include "util/win/scoped_process_suspend.h" |
| 34 | 34 |
| 35 namespace crashpad { | 35 namespace crashpad { |
| 36 namespace test { | 36 namespace test { |
| 37 namespace { | 37 namespace { |
| 38 | 38 |
| 39 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { | 39 // Runs the ExceptionHandlerServer on a background thread. |
| 40 HANDLE handle; | 40 class RunServerThread : public Thread { |
| 41 if (DuplicateHandle(GetCurrentProcess(), | 41 public: |
| 42 event, | 42 // Instantiates a thread which will invoke server->Run(delegate, pipe_name); |
| 43 process, | 43 RunServerThread(ExceptionHandlerServer* server, |
| 44 &handle, | 44 ExceptionHandlerServer::Delegate* delegate, |
| 45 SYNCHRONIZE | EVENT_MODIFY_STATE, | 45 const std::string& pipe_name) |
| 46 false, | 46 : server_(server), delegate_(delegate), pipe_name_(pipe_name) {} |
| 47 0)) { | 47 ~RunServerThread() override {} |
| 48 return handle; | 48 |
| 49 private: |
| 50 // Thread: |
| 51 void ThreadMain() override { server_->Run(delegate_, pipe_name_); } |
| 52 |
| 53 ExceptionHandlerServer* server_; |
| 54 ExceptionHandlerServer::Delegate* delegate_; |
| 55 std::string pipe_name_; |
| 56 |
| 57 DISALLOW_COPY_AND_ASSIGN(RunServerThread); |
| 58 }; |
| 59 |
| 60 // During destruction, ensures that the server is stopped and the background |
| 61 // thread joined. |
| 62 class ScopedStopServerAndJoinThread { |
| 63 public: |
| 64 ScopedStopServerAndJoinThread(ExceptionHandlerServer* server, Thread* thread) |
| 65 : server_(server), thread_(thread) {} |
| 66 ~ScopedStopServerAndJoinThread() { |
| 67 server_->Stop(); |
| 68 thread_->Join(); |
| 49 } | 69 } |
| 50 return nullptr; | |
| 51 } | |
| 52 | 70 |
| 53 class Delegate : public ExceptionHandlerServer::Delegate { | 71 private: |
| 72 ExceptionHandlerServer* server_; |
| 73 Thread* thread_; |
| 74 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); |
| 75 }; |
| 76 |
| 77 class CrashingDelegate : public ExceptionHandlerServer::Delegate { |
| 54 public: | 78 public: |
| 55 Delegate(HANDLE server_ready, HANDLE completed_test_event) | 79 CrashingDelegate(HANDLE server_ready, HANDLE completed_test_event) |
| 56 : server_ready_(server_ready), | 80 : server_ready_(server_ready), |
| 57 completed_test_event_(completed_test_event), | 81 completed_test_event_(completed_test_event), |
| 58 break_near_(0) {} | 82 break_near_(0) {} |
| 59 ~Delegate() override {} | 83 ~CrashingDelegate() override {} |
| 60 | 84 |
| 61 void set_break_near(WinVMAddress break_near) { break_near_ = break_near; } | 85 void set_break_near(WinVMAddress break_near) { break_near_ = break_near; } |
| 62 | 86 |
| 63 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); } | 87 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); } |
| 64 | 88 |
| 65 unsigned int ExceptionHandlerServerException( | 89 unsigned int ExceptionHandlerServerException( |
| 66 HANDLE process, | 90 HANDLE process, |
| 67 WinVMAddress exception_information_address) override { | 91 WinVMAddress exception_information_address) override { |
| 68 ScopedProcessSuspend suspend(process); | 92 ScopedProcessSuspend suspend(process); |
| 69 ProcessSnapshotWin snapshot; | 93 ProcessSnapshotWin snapshot; |
| 70 snapshot.Initialize(process, ProcessSuspensionState::kSuspended); | 94 snapshot.Initialize(process, ProcessSuspensionState::kSuspended); |
| 71 snapshot.InitializeException(exception_information_address); | 95 snapshot.InitializeException(exception_information_address); |
| 72 | 96 |
| 73 // Confirm the exception record was read correctly. | 97 // Confirm the exception record was read correctly. |
| 74 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u); | 98 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u); |
| 75 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT); | 99 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT); |
| 76 | 100 |
| 77 // Verify the exception happened at the expected location with a bit of | 101 // Verify the exception happened at the expected location with a bit of |
| 78 // slop space to allow for reading the current PC before the exception | 102 // slop space to allow for reading the current PC before the exception |
| 79 // happens. See CrashingChildProcess::Run(). | 103 // happens. See TestCrashingChild(). |
| 80 const uint64_t kAllowedOffset = 64; | 104 const uint64_t kAllowedOffset = 64; |
| 81 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_); | 105 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_); |
| 82 EXPECT_LT(snapshot.Exception()->ExceptionAddress(), | 106 EXPECT_LT(snapshot.Exception()->ExceptionAddress(), |
| 83 break_near_ + kAllowedOffset); | 107 break_near_ + kAllowedOffset); |
| 84 | 108 |
| 85 SetEvent(completed_test_event_); | 109 SetEvent(completed_test_event_); |
| 86 | 110 |
| 87 return snapshot.Exception()->Exception(); | 111 return snapshot.Exception()->Exception(); |
| 88 } | 112 } |
| 89 | 113 |
| 90 private: | 114 private: |
| 91 HANDLE server_ready_; // weak | 115 HANDLE server_ready_; // weak |
| 92 HANDLE completed_test_event_; // weak | 116 HANDLE completed_test_event_; // weak |
| 93 WinVMAddress break_near_; | 117 WinVMAddress break_near_; |
| 94 | 118 |
| 95 DISALLOW_COPY_AND_ASSIGN(Delegate); | 119 DISALLOW_COPY_AND_ASSIGN(CrashingDelegate); |
| 96 }; | |
| 97 | |
| 98 // Runs the ExceptionHandlerServer on a background thread. | |
| 99 class RunServerThread : public Thread { | |
| 100 public: | |
| 101 // Instantiates a thread which will invoke server->Run(delegate, pipe_name); | |
| 102 RunServerThread(ExceptionHandlerServer* server, | |
| 103 ExceptionHandlerServer::Delegate* delegate, | |
| 104 const std::string& pipe_name) | |
| 105 : server_(server), delegate_(delegate), pipe_name_(pipe_name) {} | |
| 106 ~RunServerThread() override {} | |
| 107 | |
| 108 private: | |
| 109 // Thread: | |
| 110 void ThreadMain() override { server_->Run(delegate_, pipe_name_); } | |
| 111 | |
| 112 ExceptionHandlerServer* server_; | |
| 113 ExceptionHandlerServer::Delegate* delegate_; | |
| 114 std::string pipe_name_; | |
| 115 | |
| 116 DISALLOW_COPY_AND_ASSIGN(RunServerThread); | |
| 117 }; | |
| 118 | |
| 119 // During destruction, ensures that the server is stopped and the background | |
| 120 // thread joined. | |
| 121 class ScopedStopServerAndJoinThread { | |
| 122 public: | |
| 123 ScopedStopServerAndJoinThread(ExceptionHandlerServer* server, Thread* thread) | |
| 124 : server_(server), thread_(thread) {} | |
| 125 ~ScopedStopServerAndJoinThread() { | |
| 126 server_->Stop(); | |
| 127 thread_->Join(); | |
| 128 } | |
| 129 | |
| 130 private: | |
| 131 ExceptionHandlerServer* server_; | |
| 132 Thread* thread_; | |
| 133 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); | |
| 134 }; | 120 }; |
| 135 | 121 |
| 136 void TestCrashingChild(const base::string16& directory_modification) { | 122 void TestCrashingChild(const base::string16& directory_modification) { |
| 137 // Set up the registration server on a background thread. | 123 // Set up the registration server on a background thread. |
| 138 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + | 124 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + |
| 139 base::StringPrintf("%08x", GetCurrentProcessId()); | 125 base::StringPrintf("%08x", GetCurrentProcessId()); |
| 140 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); | 126 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); |
| 141 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); | 127 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); |
| 142 Delegate delegate(server_ready.get(), completed.get()); | 128 CrashingDelegate delegate(server_ready.get(), completed.get()); |
| 143 | 129 |
| 144 ExceptionHandlerServer exception_handler_server; | 130 ExceptionHandlerServer exception_handler_server; |
| 145 RunServerThread server_thread( | 131 RunServerThread server_thread( |
| 146 &exception_handler_server, &delegate, pipe_name); | 132 &exception_handler_server, &delegate, pipe_name); |
| 147 server_thread.Start(); | 133 server_thread.Start(); |
| 148 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | 134 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( |
| 149 &exception_handler_server, &server_thread); | 135 &exception_handler_server, &server_thread); |
| 150 | 136 |
| 151 WaitForSingleObject(server_ready.get(), INFINITE); | 137 WaitForSingleObject(server_ready.get(), INFINITE); |
| 152 | 138 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 179 #if defined(ARCH_CPU_64_BITS) | 165 #if defined(ARCH_CPU_64_BITS) |
| 180 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { | 166 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { |
| 181 #ifndef NDEBUG | 167 #ifndef NDEBUG |
| 182 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug")); | 168 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug")); |
| 183 #else | 169 #else |
| 184 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release")); | 170 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release")); |
| 185 #endif | 171 #endif |
| 186 } | 172 } |
| 187 #endif // ARCH_CPU_64_BITS | 173 #endif // ARCH_CPU_64_BITS |
| 188 | 174 |
| 175 class SimulateDelegate : public ExceptionHandlerServer::Delegate { |
| 176 public: |
| 177 SimulateDelegate(HANDLE server_ready, HANDLE completed_test_event) |
| 178 : server_ready_(server_ready), |
| 179 completed_test_event_(completed_test_event), |
| 180 dump_near_(0) {} |
| 181 ~SimulateDelegate() override {} |
| 182 |
| 183 void set_dump_near(WinVMAddress dump_near) { dump_near_ = dump_near; } |
| 184 |
| 185 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); } |
| 186 |
| 187 unsigned int ExceptionHandlerServerException( |
| 188 HANDLE process, |
| 189 WinVMAddress exception_information_address) override { |
| 190 ScopedProcessSuspend suspend(process); |
| 191 ProcessSnapshotWin snapshot; |
| 192 snapshot.Initialize(process, ProcessSuspensionState::kSuspended); |
| 193 snapshot.InitializeException(exception_information_address); |
| 194 EXPECT_TRUE(snapshot.Exception()); |
| 195 EXPECT_EQ(0, snapshot.Exception()->Exception()); |
| 196 EXPECT_EQ(0, snapshot.Exception()->ExceptionAddress()); |
| 197 |
| 198 // Verify the dump was captured at the expected location with some slop |
| 199 // space. |
| 200 const uint64_t kAllowedOffset = 64; |
| 201 EXPECT_GT(snapshot.Exception()->Context()->InstructionPointer(), |
| 202 dump_near_); |
| 203 EXPECT_LT(snapshot.Exception()->Context()->InstructionPointer(), |
| 204 dump_near_ + kAllowedOffset); |
| 205 |
| 206 SetEvent(completed_test_event_); |
| 207 |
| 208 return 0; |
| 209 } |
| 210 |
| 211 private: |
| 212 HANDLE server_ready_; // weak |
| 213 HANDLE completed_test_event_; // weak |
| 214 WinVMAddress dump_near_; |
| 215 |
| 216 DISALLOW_COPY_AND_ASSIGN(SimulateDelegate); |
| 217 }; |
| 218 |
| 219 void TestDumpWithoutCrashingChild( |
| 220 const base::string16& directory_modification) { |
| 221 // Set up the registration server on a background thread. |
| 222 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + |
| 223 base::StringPrintf("%08x", GetCurrentProcessId()); |
| 224 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); |
| 225 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); |
| 226 SimulateDelegate delegate(server_ready.get(), completed.get()); |
| 227 |
| 228 ExceptionHandlerServer exception_handler_server; |
| 229 RunServerThread server_thread( |
| 230 &exception_handler_server, &delegate, pipe_name); |
| 231 server_thread.Start(); |
| 232 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( |
| 233 &exception_handler_server, &server_thread); |
| 234 |
| 235 WaitForSingleObject(server_ready.get(), INFINITE); |
| 236 |
| 237 // Spawn a child process, passing it the pipe name to connect to. |
| 238 base::FilePath test_executable = Paths::Executable(); |
| 239 std::wstring child_test_executable = |
| 240 test_executable.DirName() |
| 241 .Append(directory_modification) |
| 242 .Append(test_executable.BaseName().RemoveFinalExtension().value() + |
| 243 L"_dump_without_crashing.exe") |
| 244 .value(); |
| 245 ChildLauncher child(child_test_executable, base::UTF8ToUTF16(pipe_name)); |
| 246 child.Start(); |
| 247 |
| 248 // The child tells us (approximately) where it will capture a dump. |
| 249 WinVMAddress dump_near_address; |
| 250 LoggingReadFile(child.stdout_read_handle(), |
| 251 &dump_near_address, |
| 252 sizeof(dump_near_address)); |
| 253 delegate.set_dump_near(dump_near_address); |
| 254 |
| 255 // Wait for the child to crash and the exception information to be validated. |
| 256 WaitForSingleObject(completed.get(), INFINITE); |
| 257 } |
| 258 |
| 259 TEST(SimulateCrash, ChildDumpWithoutCrashing) { |
| 260 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL(".")); |
| 261 } |
| 262 |
| 263 #if defined(ARCH_CPU_64_BITS) |
| 264 TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) { |
| 265 #ifndef NDEBUG |
| 266 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug")); |
| 267 #else |
| 268 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release")); |
| 269 #endif |
| 270 } |
| 271 #endif // ARCH_CPU_64_BITS |
| 272 |
| 189 } // namespace | 273 } // namespace |
| 190 } // namespace test | 274 } // namespace test |
| 191 } // namespace crashpad | 275 } // namespace crashpad |
| OLD | NEW |