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

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

Issue 1126413008: win: Implement exception snapshot (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: fixes2 Created 5 years, 4 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/win/exception_snapshot_win.cc ('k') | snapshot/win/process_reader_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/exception_snapshot_win.h"
16
17 #include <string>
18
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.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"
25 #include "snapshot/win/process_reader_win.h"
26 #include "snapshot/win/process_snapshot_win.h"
27 #include "test/win/win_child_process.h"
28 #include "util/thread/thread.h"
29 #include "util/win/scoped_handle.h"
30
31 namespace crashpad {
32 namespace test {
33 namespace {
34
35 HANDLE DuplicateEvent(HANDLE process, HANDLE event) {
36 HANDLE handle;
37 if (DuplicateHandle(GetCurrentProcess(),
38 event,
39 process,
40 &handle,
41 SYNCHRONIZE | EVENT_MODIFY_STATE,
42 false,
43 0)) {
44 return handle;
45 }
46 return nullptr;
47 }
48
49 class ExceptionSnapshotWinTest : public testing::Test {
50 public:
51 class Delegate : public RegistrationServer::Delegate {
52 public:
53 Delegate()
54 : crashpad_info_address_(0),
55 client_process_(),
56 started_event_(CreateEvent(nullptr, false, false, nullptr)),
57 request_dump_event_(CreateEvent(nullptr, false, false, nullptr)),
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
64 ~Delegate() override {
65 }
66
67 void OnStarted() override {
68 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(started_event_.get(), 0));
69 SetEvent(started_event_.get());
70 }
71
72 bool RegisterClient(ScopedKernelHANDLE client_process,
73 WinVMAddress crashpad_info_address,
74 HANDLE* request_dump_event,
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.
97 ProcessReaderWin process_reader;
98 ASSERT_TRUE(process_reader.Initialize(client_process_.get()));
99 CrashpadInfo crashpad_info;
100 ASSERT_TRUE(process_reader.ReadMemory(
101 crashpad_info_address_, sizeof(crashpad_info), &crashpad_info));
102 ProcessSnapshotWin snapshot;
103 snapshot.Initialize(client_process_.get());
104 snapshot.InitializeException(
105 crashpad_info.thread_id(),
106 reinterpret_cast<WinVMAddress>(crashpad_info.exception_pointers()));
107
108 // Confirm the exception record was read correctly.
109 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u);
110 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT);
111
112 // 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
114 // happens. See CrashingChildProcess::Run().
115 const uint64_t kAllowedOffset = 64;
116 EXPECT_GT(snapshot.Exception()->ExceptionAddress(),
117 reinterpret_cast<uint64_t>(break_near));
118 EXPECT_LT(snapshot.Exception()->ExceptionAddress(),
119 reinterpret_cast<uint64_t>(break_near) + kAllowedOffset);
120
121 // Notify the child that we're done.
122 SetEvent(dump_complete_event_.get());
123 }
124
125 ScopedKernelHANDLE* request_dump_event() { return &request_dump_event_; }
126 ScopedKernelHANDLE* dump_complete_event() { return &dump_complete_event_; }
127
128 private:
129 WinVMAddress crashpad_info_address_;
130 ScopedKernelHANDLE client_process_;
131 ScopedKernelHANDLE started_event_;
132 ScopedKernelHANDLE request_dump_event_;
133 ScopedKernelHANDLE dump_complete_event_;
134 };
135 };
136
137 // Runs the RegistrationServer on a background thread.
138 class RunServerThread : public Thread {
139 public:
140 // Instantiates a thread which will invoke server->Run(pipe_name, delegate).
141 RunServerThread(RegistrationServer* server,
142 const base::string16& pipe_name,
143 RegistrationServer::Delegate* delegate)
144 : server_(server), pipe_name_(pipe_name), delegate_(delegate) {}
145 ~RunServerThread() override {}
146
147 private:
148 // Thread:
149 void ThreadMain() override { server_->Run(pipe_name_, delegate_); }
150
151 RegistrationServer* server_;
152 base::string16 pipe_name_;
153 RegistrationServer::Delegate* delegate_;
154
155 DISALLOW_COPY_AND_ASSIGN(RunServerThread);
156 };
157
158 // During destruction, ensures that the server is stopped and the background
159 // thread joined.
160 class ScopedStopServerAndJoinThread {
161 public:
162 explicit ScopedStopServerAndJoinThread(RegistrationServer* server,
163 Thread* thread)
164 : server_(server), thread_(thread) {}
165 ~ScopedStopServerAndJoinThread() {
166 server_->Stop();
167 thread_->Join();
168 }
169
170 private:
171 RegistrationServer* server_;
172 Thread* thread_;
173 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread);
174 };
175
176 std::string ReadString(FileHandle handle) {
177 size_t length = 0;
178 EXPECT_TRUE(LoggingReadFile(handle, &length, sizeof(length)));
179 scoped_ptr<char[]> buffer(new char[length]);
180 EXPECT_TRUE(LoggingReadFile(handle, &buffer[0], length));
181 return std::string(&buffer[0], length);
182 }
183
184 void WriteString(FileHandle handle, const std::string& str) {
185 size_t length = str.size();
186 EXPECT_TRUE(LoggingWriteFile(handle, &length, sizeof(length)));
187 EXPECT_TRUE(LoggingWriteFile(handle, &str[0], length));
188 }
189
190 __declspec(noinline) void* CurrentAddress() {
191 return _ReturnAddress();
192 }
193
194 class CrashingChildProcess final : public WinChildProcess {
195 public:
196 CrashingChildProcess() : WinChildProcess() {}
197 ~CrashingChildProcess() {}
198
199 private:
200 int Run() override {
201 std::string pipe_name = ReadString(ReadPipeHandle());
202 CrashpadClient client;
203 EXPECT_TRUE(client.SetHandler(pipe_name));
204 EXPECT_TRUE(client.UseHandler());
205 // Save the address where we're about to crash so the exception handler can
206 // verify it's in approximately the right location (with a bit of fudge for
207 // the code between here and the __debugbreak()).
208 void* break_address = CurrentAddress();
209 LoggingWriteFile(WritePipeHandle(), &break_address, sizeof(break_address));
210 __debugbreak();
211 return 0;
212 };
213 };
214
215 TEST_F(ExceptionSnapshotWinTest, ChildCrash) {
216 // Set up the registration server on a background thread.
217 RegistrationServer server;
218 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" +
219 base::StringPrintf("%08x", GetCurrentProcessId());
220 base::string16 pipe_name_16 = base::UTF8ToUTF16(pipe_name);
221 Delegate delegate;
222 RunServerThread server_thread(&server, pipe_name_16, &delegate);
223 server_thread.Start();
224 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
225 &server, &server_thread);
226 ASSERT_NO_FATAL_FAILURE(delegate.WaitForStart());
227
228 // Spawn a child process that immediately crashes.
229 WinChildProcess::EntryPoint<CrashingChildProcess>();
230 scoped_ptr<WinChildProcess::Handles> handle = WinChildProcess::Launch();
231 WriteString(handle->write.get(), pipe_name);
232
233 void* break_near_address;
234 LoggingReadFile(
235 handle->read.get(), &break_near_address, sizeof(break_near_address));
236
237 // Verify the exception information is as expected.
238 delegate.WaitForDumpRequestAndValidateException(break_near_address);
239 }
240
241 } // namespace
242 } // namespace test
243 } // namespace crashpad
OLDNEW
« no previous file with comments | « snapshot/win/exception_snapshot_win.cc ('k') | snapshot/win/process_reader_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698