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

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

Issue 1356383002: win: Implement CRASHPAD_SIMULATE_CRASH() (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: . 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
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,
(...skipping 18 matching lines...) Expand all
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 void 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
87 return snapshot.Exception()->Exception();
88 } 110 }
89 111
90 private: 112 private:
91 HANDLE server_ready_; // weak 113 HANDLE server_ready_; // weak
92 HANDLE completed_test_event_; // weak 114 HANDLE completed_test_event_; // weak
93 WinVMAddress break_near_; 115 WinVMAddress break_near_;
94 116
95 DISALLOW_COPY_AND_ASSIGN(Delegate); 117 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 }; 118 };
135 119
136 void TestCrashingChild(const base::string16& directory_modification) { 120 void TestCrashingChild(const base::string16& directory_modification) {
137 // Set up the registration server on a background thread. 121 // Set up the registration server on a background thread.
138 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + 122 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" +
139 base::StringPrintf("%08x", GetCurrentProcessId()); 123 base::StringPrintf("%08x", GetCurrentProcessId());
140 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); 124 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
141 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); 125 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr));
142 Delegate delegate(server_ready.get(), completed.get()); 126 CrashingDelegate delegate(server_ready.get(), completed.get());
143 127
144 ExceptionHandlerServer exception_handler_server; 128 ExceptionHandlerServer exception_handler_server;
145 RunServerThread server_thread( 129 RunServerThread server_thread(
146 &exception_handler_server, &delegate, pipe_name); 130 &exception_handler_server, &delegate, pipe_name);
147 server_thread.Start(); 131 server_thread.Start();
148 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( 132 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
149 &exception_handler_server, &server_thread); 133 &exception_handler_server, &server_thread);
150 134
151 WaitForSingleObject(server_ready.get(), INFINITE); 135 WaitForSingleObject(server_ready.get(), INFINITE);
152 136
(...skipping 26 matching lines...) Expand all
179 #if defined(ARCH_CPU_64_BITS) 163 #if defined(ARCH_CPU_64_BITS)
180 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { 164 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) {
181 #ifndef NDEBUG 165 #ifndef NDEBUG
182 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug")); 166 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug"));
183 #else 167 #else
184 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release")); 168 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release"));
185 #endif 169 #endif
186 } 170 }
187 #endif // ARCH_CPU_64_BITS 171 #endif // ARCH_CPU_64_BITS
188 172
173 class SimulateDelegate : public ExceptionHandlerServer::Delegate {
174 public:
175 SimulateDelegate(HANDLE server_ready, HANDLE completed_test_event)
176 : server_ready_(server_ready),
177 completed_test_event_(completed_test_event),
178 dump_near_(0) {}
179 ~SimulateDelegate() override {}
180
181 void set_dump_near(WinVMAddress dump_near) { dump_near_ = dump_near; }
182
183 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); }
184
185 void ExceptionHandlerServerException(
186 HANDLE process,
187 WinVMAddress exception_information_address) override {
188 ScopedProcessSuspend suspend(process);
189 ProcessSnapshotWin snapshot;
190 snapshot.Initialize(process, ProcessSuspensionState::kSuspended);
191 snapshot.InitializeException(exception_information_address);
192 ASSERT_TRUE(snapshot.Exception());
193 EXPECT_EQ(0, snapshot.Exception()->Exception());
194 EXPECT_EQ(0, snapshot.Exception()->ExceptionAddress());
195
196 // Verify the dump was captured at the expected location with some slop
197 // space.
198 const uint64_t kAllowedOffset = 64;
199 EXPECT_GT(snapshot.Exception()->Context()->InstructionPointer(),
200 dump_near_);
201 EXPECT_LT(snapshot.Exception()->Context()->InstructionPointer(),
202 dump_near_ + kAllowedOffset);
203
204 SetEvent(completed_test_event_);
205 }
206
207 private:
208 HANDLE server_ready_; // weak
209 HANDLE completed_test_event_; // weak
210 WinVMAddress dump_near_;
211
212 DISALLOW_COPY_AND_ASSIGN(SimulateDelegate);
213 };
214
215
216 void TestDumpWithoutCrashingChild(
217 const base::string16& directory_modification) {
218 // Set up the registration server on a background thread.
219 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" +
220 base::StringPrintf("%08x", GetCurrentProcessId());
221 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
222 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr));
223 SimulateDelegate delegate(server_ready.get(), completed.get());
224
225 ExceptionHandlerServer exception_handler_server;
226 RunServerThread server_thread(
227 &exception_handler_server, &delegate, pipe_name);
228 server_thread.Start();
229 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
230 &exception_handler_server, &server_thread);
231
232 WaitForSingleObject(server_ready.get(), INFINITE);
233
234 // Spawn a child process, passing it the pipe name to connect to.
235 base::FilePath test_executable = Paths::Executable();
236 std::wstring child_test_executable =
237 test_executable.DirName()
238 .Append(directory_modification)
239 .Append(test_executable.BaseName().RemoveFinalExtension().value() +
240 L"_dump_without_crashing.exe")
241 .value();
242 ChildLauncher child(child_test_executable, base::UTF8ToUTF16(pipe_name));
243 child.Start();
244
245 // The child tells us (approximately) where it will capture a dump.
246 WinVMAddress dump_near_address;
247 LoggingReadFile(child.stdout_read_handle(),
248 &dump_near_address,
249 sizeof(dump_near_address));
250 delegate.set_dump_near(dump_near_address);
251
252 // Wait for the child to crash and the exception information to be validated.
253 WaitForSingleObject(completed.get(), INFINITE);
254 }
255
256 TEST(SimulateCrash, ChildDumpWithoutCrashing) {
257 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL("."));
258 }
259
260 #if defined(ARCH_CPU_64_BITS)
261 TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) {
262 #ifndef NDEBUG
263 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug"));
264 #else
265 TestDumpWithoutCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release"));
266 #endif
267 }
268 #endif // ARCH_CPU_64_BITS
269
189 } // namespace 270 } // namespace
190 } // namespace test 271 } // namespace test
191 } // namespace crashpad 272 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698