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, |
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 "snapshot/win/exception_snapshot_win.h" | 15 #include "snapshot/win/exception_snapshot_win.h" |
16 | 16 |
17 #include <string> | 17 #include <string> |
18 | 18 |
19 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
20 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
21 #include "client/crashpad_client.h" | 21 #include "client/crashpad_client.h" |
22 #include "client/crashpad_info.h" | |
23 #include "handler/win/registration_server.h" | |
24 #include "gtest/gtest.h" | 22 #include "gtest/gtest.h" |
25 #include "snapshot/win/process_reader_win.h" | 23 #include "snapshot/win/process_reader_win.h" |
26 #include "snapshot/win/process_snapshot_win.h" | 24 #include "snapshot/win/process_snapshot_win.h" |
27 #include "test/win/win_child_process.h" | 25 #include "test/win/win_child_process.h" |
28 #include "util/thread/thread.h" | 26 #include "util/thread/thread.h" |
| 27 #include "util/win/exception_handler_server.h" |
| 28 #include "util/win/registration_protocol_win.h" |
29 #include "util/win/scoped_handle.h" | 29 #include "util/win/scoped_handle.h" |
30 | 30 |
31 namespace crashpad { | 31 namespace crashpad { |
32 namespace test { | 32 namespace test { |
33 namespace { | 33 namespace { |
34 | 34 |
35 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { | 35 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { |
36 HANDLE handle; | 36 HANDLE handle; |
37 if (DuplicateHandle(GetCurrentProcess(), | 37 if (DuplicateHandle(GetCurrentProcess(), |
38 event, | 38 event, |
39 process, | 39 process, |
40 &handle, | 40 &handle, |
41 SYNCHRONIZE | EVENT_MODIFY_STATE, | 41 SYNCHRONIZE | EVENT_MODIFY_STATE, |
42 false, | 42 false, |
43 0)) { | 43 0)) { |
44 return handle; | 44 return handle; |
45 } | 45 } |
46 return nullptr; | 46 return nullptr; |
47 } | 47 } |
48 | 48 |
49 class ExceptionSnapshotWinTest : public testing::Test { | 49 class ExceptionSnapshotWinTest : public testing::Test { |
50 public: | 50 public: |
51 class Delegate : public RegistrationServer::Delegate { | 51 class Delegate : public ExceptionHandlerServer::Delegate { |
52 public: | 52 public: |
53 Delegate() | 53 Delegate(HANDLE server_ready, HANDLE completed_test_event) |
54 : crashpad_info_address_(0), | 54 : server_ready_(server_ready), |
55 client_process_(), | 55 completed_test_event_(completed_test_event), |
56 started_event_(CreateEvent(nullptr, false, false, nullptr)), | 56 break_near_(nullptr) {} |
57 request_dump_event_(CreateEvent(nullptr, false, false, nullptr)), | 57 ~Delegate() override {} |
58 dump_complete_event_(CreateEvent(nullptr, true, false, nullptr)) { | |
59 EXPECT_TRUE(started_event_.is_valid()); | |
60 EXPECT_TRUE(request_dump_event_.is_valid()); | |
61 EXPECT_TRUE(dump_complete_event_.is_valid()); | |
62 } | |
63 | 58 |
64 ~Delegate() override { | 59 void set_break_near(void* break_near) { break_near_ = break_near; } |
65 } | |
66 | 60 |
67 void OnStarted() override { | 61 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); } |
68 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(started_event_.get(), 0)); | |
69 SetEvent(started_event_.get()); | |
70 } | |
71 | 62 |
72 bool RegisterClient(ScopedKernelHANDLE client_process, | 63 unsigned int ExceptionHandlerServerException( |
73 WinVMAddress crashpad_info_address, | 64 HANDLE process, |
74 HANDLE* request_dump_event, | 65 WinVMAddress exception_information_address) override { |
75 HANDLE* dump_complete_event) override { | |
76 client_process_ = client_process.Pass(); | |
77 crashpad_info_address_ = crashpad_info_address; | |
78 *request_dump_event = | |
79 DuplicateEvent(client_process_.get(), request_dump_event_.get()); | |
80 *dump_complete_event = | |
81 DuplicateEvent(client_process_.get(), dump_complete_event_.get()); | |
82 return true; | |
83 } | |
84 | |
85 void WaitForStart() { | |
86 DWORD wait_result = WaitForSingleObject(started_event_.get(), INFINITE); | |
87 if (wait_result == WAIT_FAILED) | |
88 PLOG(ERROR); | |
89 ASSERT_EQ(wait_result, WAIT_OBJECT_0); | |
90 } | |
91 | |
92 void WaitForDumpRequestAndValidateException(void* break_near) { | |
93 // Wait until triggered, and then grab information from the child. | |
94 WaitForSingleObject(request_dump_event_.get(), INFINITE); | |
95 | |
96 // Snapshot the process and exception. | 66 // Snapshot the process and exception. |
97 ProcessReaderWin process_reader; | 67 ProcessReaderWin process_reader; |
98 ASSERT_TRUE(process_reader.Initialize(client_process_.get())); | 68 EXPECT_TRUE(process_reader.Initialize(process)); |
99 CrashpadInfo crashpad_info; | 69 if (HasFatalFailure()) |
100 ASSERT_TRUE(process_reader.ReadMemory( | 70 return 0xffffffff; |
101 crashpad_info_address_, sizeof(crashpad_info), &crashpad_info)); | 71 ExceptionInformation exception_information; |
| 72 EXPECT_TRUE( |
| 73 process_reader.ReadMemory(exception_information_address, |
| 74 sizeof(exception_information), |
| 75 &exception_information)); |
| 76 if (HasFatalFailure()) |
| 77 return 0xffffffff; |
102 ProcessSnapshotWin snapshot; | 78 ProcessSnapshotWin snapshot; |
103 snapshot.Initialize(client_process_.get()); | 79 snapshot.Initialize(process); |
104 snapshot.InitializeException( | 80 snapshot.InitializeException(exception_information.thread_id, |
105 crashpad_info.thread_id(), | 81 exception_information.exception_pointers); |
106 reinterpret_cast<WinVMAddress>(crashpad_info.exception_pointers())); | |
107 | 82 |
108 // Confirm the exception record was read correctly. | 83 // Confirm the exception record was read correctly. |
109 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u); | 84 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u); |
110 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT); | 85 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT); |
111 | 86 |
112 // Verify the exception happened at the expected location with a bit of | 87 // Verify the exception happened at the expected location with a bit of |
113 // slop space to allow for reading the current PC before the exception | 88 // slop space to allow for reading the current PC before the exception |
114 // happens. See CrashingChildProcess::Run(). | 89 // happens. See CrashingChildProcess::Run(). |
115 const uint64_t kAllowedOffset = 64; | 90 const uint64_t kAllowedOffset = 64; |
116 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), | 91 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), |
117 reinterpret_cast<uint64_t>(break_near)); | 92 reinterpret_cast<uint64_t>(break_near_)); |
118 EXPECT_LT(snapshot.Exception()->ExceptionAddress(), | 93 EXPECT_LT(snapshot.Exception()->ExceptionAddress(), |
119 reinterpret_cast<uint64_t>(break_near) + kAllowedOffset); | 94 reinterpret_cast<uint64_t>(break_near_) + kAllowedOffset); |
120 | 95 |
121 // Notify the child that we're done. | 96 SetEvent(completed_test_event_); |
122 SetEvent(dump_complete_event_.get()); | 97 |
| 98 return snapshot.Exception()->Exception(); |
123 } | 99 } |
124 | 100 |
125 ScopedKernelHANDLE* request_dump_event() { return &request_dump_event_; } | 101 private: |
126 ScopedKernelHANDLE* dump_complete_event() { return &dump_complete_event_; } | 102 HANDLE server_ready_; // weak |
| 103 HANDLE completed_test_event_; // weak |
| 104 void* break_near_; |
127 | 105 |
128 private: | 106 DISALLOW_COPY_AND_ASSIGN(Delegate); |
129 WinVMAddress crashpad_info_address_; | |
130 ScopedKernelHANDLE client_process_; | |
131 ScopedKernelHANDLE started_event_; | |
132 ScopedKernelHANDLE request_dump_event_; | |
133 ScopedKernelHANDLE dump_complete_event_; | |
134 }; | 107 }; |
| 108 |
| 109 private: |
| 110 ScopedKernelHANDLE exception_happened_; |
135 }; | 111 }; |
136 | 112 |
137 // Runs the RegistrationServer on a background thread. | 113 // Runs the ExceptionHandlerServer on a background thread. |
138 class RunServerThread : public Thread { | 114 class RunServerThread : public Thread { |
139 public: | 115 public: |
140 // Instantiates a thread which will invoke server->Run(pipe_name, delegate). | 116 // Instantiates a thread which will invoke server->Run(pipe_name); |
141 RunServerThread(RegistrationServer* server, | 117 explicit RunServerThread(ExceptionHandlerServer* server, |
142 const base::string16& pipe_name, | 118 const std::string& pipe_name) |
143 RegistrationServer::Delegate* delegate) | 119 : server_(server), pipe_name_(pipe_name) {} |
144 : server_(server), pipe_name_(pipe_name), delegate_(delegate) {} | |
145 ~RunServerThread() override {} | 120 ~RunServerThread() override {} |
146 | 121 |
147 private: | 122 private: |
148 // Thread: | 123 // Thread: |
149 void ThreadMain() override { server_->Run(pipe_name_, delegate_); } | 124 void ThreadMain() override { server_->Run(pipe_name_); } |
150 | 125 |
151 RegistrationServer* server_; | 126 ExceptionHandlerServer* server_; |
152 base::string16 pipe_name_; | 127 std::string pipe_name_; |
153 RegistrationServer::Delegate* delegate_; | |
154 | 128 |
155 DISALLOW_COPY_AND_ASSIGN(RunServerThread); | 129 DISALLOW_COPY_AND_ASSIGN(RunServerThread); |
156 }; | 130 }; |
157 | 131 |
158 // During destruction, ensures that the server is stopped and the background | 132 // During destruction, ensures that the server is stopped and the background |
159 // thread joined. | 133 // thread joined. |
160 class ScopedStopServerAndJoinThread { | 134 class ScopedStopServerAndJoinThread { |
161 public: | 135 public: |
162 explicit ScopedStopServerAndJoinThread(RegistrationServer* server, | 136 explicit ScopedStopServerAndJoinThread(ExceptionHandlerServer* server, |
163 Thread* thread) | 137 Thread* thread) |
164 : server_(server), thread_(thread) {} | 138 : server_(server), thread_(thread) {} |
165 ~ScopedStopServerAndJoinThread() { | 139 ~ScopedStopServerAndJoinThread() { |
166 server_->Stop(); | 140 server_->Stop(); |
167 thread_->Join(); | 141 thread_->Join(); |
168 } | 142 } |
169 | 143 |
170 private: | 144 private: |
171 RegistrationServer* server_; | 145 ExceptionHandlerServer* server_; |
172 Thread* thread_; | 146 Thread* thread_; |
173 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); | 147 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); |
174 }; | 148 }; |
175 | 149 |
176 std::string ReadString(FileHandle handle) { | 150 std::string ReadString(FileHandle handle) { |
177 size_t length = 0; | 151 size_t length = 0; |
178 EXPECT_TRUE(LoggingReadFile(handle, &length, sizeof(length))); | 152 EXPECT_TRUE(LoggingReadFile(handle, &length, sizeof(length))); |
179 scoped_ptr<char[]> buffer(new char[length]); | 153 scoped_ptr<char[]> buffer(new char[length]); |
180 EXPECT_TRUE(LoggingReadFile(handle, &buffer[0], length)); | 154 EXPECT_TRUE(LoggingReadFile(handle, &buffer[0], length)); |
181 return std::string(&buffer[0], length); | 155 return std::string(&buffer[0], length); |
(...skipping 24 matching lines...) Expand all Loading... |
206 // verify it's in approximately the right location (with a bit of fudge for | 180 // verify it's in approximately the right location (with a bit of fudge for |
207 // the code between here and the __debugbreak()). | 181 // the code between here and the __debugbreak()). |
208 void* break_address = CurrentAddress(); | 182 void* break_address = CurrentAddress(); |
209 LoggingWriteFile(WritePipeHandle(), &break_address, sizeof(break_address)); | 183 LoggingWriteFile(WritePipeHandle(), &break_address, sizeof(break_address)); |
210 __debugbreak(); | 184 __debugbreak(); |
211 return 0; | 185 return 0; |
212 }; | 186 }; |
213 }; | 187 }; |
214 | 188 |
215 TEST_F(ExceptionSnapshotWinTest, ChildCrash) { | 189 TEST_F(ExceptionSnapshotWinTest, ChildCrash) { |
| 190 // Spawn a child process that will immediately crash (once we let it |
| 191 // run below by telling it what to connect to). |
| 192 WinChildProcess::EntryPoint<CrashingChildProcess>(); |
| 193 scoped_ptr<WinChildProcess::Handles> handle = WinChildProcess::Launch(); |
| 194 |
216 // Set up the registration server on a background thread. | 195 // Set up the registration server on a background thread. |
217 RegistrationServer server; | |
218 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + | 196 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + |
219 base::StringPrintf("%08x", GetCurrentProcessId()); | 197 base::StringPrintf("%08x", GetCurrentProcessId()); |
220 base::string16 pipe_name_16 = base::UTF8ToUTF16(pipe_name); | 198 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); |
221 Delegate delegate; | 199 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); |
222 RunServerThread server_thread(&server, pipe_name_16, &delegate); | 200 Delegate delegate(server_ready.get(), completed.get()); |
| 201 |
| 202 ExceptionHandlerServer exception_handler_server(&delegate); |
| 203 RunServerThread server_thread(&exception_handler_server, pipe_name); |
223 server_thread.Start(); | 204 server_thread.Start(); |
224 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | 205 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( |
225 &server, &server_thread); | 206 &exception_handler_server, &server_thread); |
226 ASSERT_NO_FATAL_FAILURE(delegate.WaitForStart()); | |
227 | 207 |
228 // Spawn a child process that immediately crashes. | 208 WaitForSingleObject(server_ready.get(), INFINITE); |
229 WinChildProcess::EntryPoint<CrashingChildProcess>(); | 209 // Allow the child to continue and tell it where to connect to. |
230 scoped_ptr<WinChildProcess::Handles> handle = WinChildProcess::Launch(); | |
231 WriteString(handle->write.get(), pipe_name); | 210 WriteString(handle->write.get(), pipe_name); |
232 | 211 |
| 212 // The child tells us (approximately) where it will crash. |
233 void* break_near_address; | 213 void* break_near_address; |
234 LoggingReadFile( | 214 LoggingReadFile( |
235 handle->read.get(), &break_near_address, sizeof(break_near_address)); | 215 handle->read.get(), &break_near_address, sizeof(break_near_address)); |
| 216 delegate.set_break_near(break_near_address); |
236 | 217 |
237 // Verify the exception information is as expected. | 218 // Wait for the child to crash and the exception information to be validated. |
238 delegate.WaitForDumpRequestAndValidateException(break_near_address); | 219 WaitForSingleObject(completed.get(), INFINITE); |
239 } | 220 } |
240 | 221 |
241 } // namespace | 222 } // namespace |
242 } // namespace test | 223 } // namespace test |
243 } // namespace crashpad | 224 } // namespace crashpad |
OLD | NEW |