Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(439)

Side by Side Diff: snapshot/win/exception_snapshot_win_test.cc

Issue 1301853002: win: Crash handler server (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: oops Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « snapshot/snapshot_test.gyp ('k') | util/util.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « snapshot/snapshot_test.gyp ('k') | util/util.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698