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

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

Issue 1349313003: win: support x64 reading x86 (wow64) (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: mac 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/win/exception_snapshot_win.cc ('k') | snapshot/win/process_reader_win.h » ('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/files/file_path.h"
19 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
21 #include "base/strings/string16.h"
20 #include "base/strings/utf_string_conversions.h" 22 #include "base/strings/utf_string_conversions.h"
21 #include "client/crashpad_client.h" 23 #include "client/crashpad_client.h"
22 #include "gtest/gtest.h" 24 #include "gtest/gtest.h"
23 #include "snapshot/win/process_snapshot_win.h" 25 #include "snapshot/win/process_snapshot_win.h"
26 #include "test/paths.h"
24 #include "test/win/win_child_process.h" 27 #include "test/win/win_child_process.h"
25 #include "util/thread/thread.h" 28 #include "util/thread/thread.h"
26 #include "util/win/exception_handler_server.h" 29 #include "util/win/exception_handler_server.h"
27 #include "util/win/registration_protocol_win.h" 30 #include "util/win/registration_protocol_win.h"
28 #include "util/win/scoped_handle.h" 31 #include "util/win/scoped_handle.h"
29 #include "util/win/scoped_process_suspend.h" 32 #include "util/win/scoped_process_suspend.h"
30 33
31 namespace crashpad { 34 namespace crashpad {
32 namespace test { 35 namespace test {
33 namespace { 36 namespace {
34 37
35 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { 38 HANDLE DuplicateEvent(HANDLE process, HANDLE event) {
36 HANDLE handle; 39 HANDLE handle;
37 if (DuplicateHandle(GetCurrentProcess(), 40 if (DuplicateHandle(GetCurrentProcess(),
38 event, 41 event,
39 process, 42 process,
40 &handle, 43 &handle,
41 SYNCHRONIZE | EVENT_MODIFY_STATE, 44 SYNCHRONIZE | EVENT_MODIFY_STATE,
42 false, 45 false,
43 0)) { 46 0)) {
44 return handle; 47 return handle;
45 } 48 }
46 return nullptr; 49 return nullptr;
47 } 50 }
48 51
49 class ExceptionSnapshotWinTest : public testing::Test { 52 class Delegate : public ExceptionHandlerServer::Delegate {
50 public: 53 public:
51 class Delegate : public ExceptionHandlerServer::Delegate { 54 Delegate(HANDLE server_ready, HANDLE completed_test_event)
52 public: 55 : server_ready_(server_ready),
53 Delegate(HANDLE server_ready, HANDLE completed_test_event) 56 completed_test_event_(completed_test_event),
54 : server_ready_(server_ready), 57 break_near_(0) {}
55 completed_test_event_(completed_test_event), 58 ~Delegate() override {}
56 break_near_(nullptr) {}
57 ~Delegate() override {}
58 59
59 void set_break_near(void* break_near) { break_near_ = break_near; } 60 void set_break_near(WinVMAddress break_near) { break_near_ = break_near; }
60 61
61 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); } 62 void ExceptionHandlerServerStarted() override { SetEvent(server_ready_); }
62 63
63 unsigned int ExceptionHandlerServerException( 64 unsigned int ExceptionHandlerServerException(
64 HANDLE process, 65 HANDLE process,
65 WinVMAddress exception_information_address) override { 66 WinVMAddress exception_information_address) override {
66 ScopedProcessSuspend suspend(process); 67 ScopedProcessSuspend suspend(process);
67 ProcessSnapshotWin snapshot; 68 ProcessSnapshotWin snapshot;
68 snapshot.Initialize(process, ProcessSuspensionState::kSuspended); 69 snapshot.Initialize(process, ProcessSuspensionState::kSuspended);
69 snapshot.InitializeException(exception_information_address); 70 snapshot.InitializeException(exception_information_address);
70 71
71 // Confirm the exception record was read correctly. 72 // Confirm the exception record was read correctly.
72 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u); 73 EXPECT_NE(snapshot.Exception()->ThreadID(), 0u);
73 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT); 74 EXPECT_EQ(snapshot.Exception()->Exception(), EXCEPTION_BREAKPOINT);
74 75
75 // Verify the exception happened at the expected location with a bit of 76 // Verify the exception happened at the expected location with a bit of
76 // slop space to allow for reading the current PC before the exception 77 // slop space to allow for reading the current PC before the exception
77 // happens. See CrashingChildProcess::Run(). 78 // happens. See CrashingChildProcess::Run().
78 const uint64_t kAllowedOffset = 64; 79 const uint64_t kAllowedOffset = 64;
79 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), 80 EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_);
80 reinterpret_cast<uint64_t>(break_near_)); 81 EXPECT_LT(snapshot.Exception()->ExceptionAddress(),
81 EXPECT_LT(snapshot.Exception()->ExceptionAddress(), 82 break_near_ + kAllowedOffset);
82 reinterpret_cast<uint64_t>(break_near_) + kAllowedOffset);
83 83
84 SetEvent(completed_test_event_); 84 SetEvent(completed_test_event_);
85 85
86 return snapshot.Exception()->Exception(); 86 return snapshot.Exception()->Exception();
87 } 87 }
88
89 private:
90 HANDLE server_ready_; // weak
91 HANDLE completed_test_event_; // weak
92 void* break_near_;
93
94 DISALLOW_COPY_AND_ASSIGN(Delegate);
95 };
96 88
97 private: 89 private:
98 ScopedKernelHANDLE exception_happened_; 90 HANDLE server_ready_; // weak
91 HANDLE completed_test_event_; // weak
92 WinVMAddress break_near_;
93
94 DISALLOW_COPY_AND_ASSIGN(Delegate);
99 }; 95 };
100 96
101 // Runs the ExceptionHandlerServer on a background thread. 97 // Runs the ExceptionHandlerServer on a background thread.
102 class RunServerThread : public Thread { 98 class RunServerThread : public Thread {
103 public: 99 public:
104 // Instantiates a thread which will invoke server->Run(delegate, pipe_name); 100 // Instantiates a thread which will invoke server->Run(delegate, pipe_name);
105 RunServerThread(ExceptionHandlerServer* server, 101 RunServerThread(ExceptionHandlerServer* server,
106 ExceptionHandlerServer::Delegate* delegate, 102 ExceptionHandlerServer::Delegate* delegate,
107 const std::string& pipe_name) 103 const std::string& pipe_name)
108 : server_(server), delegate_(delegate), pipe_name_(pipe_name) {} 104 : server_(server), delegate_(delegate), pipe_name_(pipe_name) {}
(...skipping 20 matching lines...) Expand all
129 server_->Stop(); 125 server_->Stop();
130 thread_->Join(); 126 thread_->Join();
131 } 127 }
132 128
133 private: 129 private:
134 ExceptionHandlerServer* server_; 130 ExceptionHandlerServer* server_;
135 Thread* thread_; 131 Thread* thread_;
136 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); 132 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread);
137 }; 133 };
138 134
139 std::string ReadString(FileHandle handle) { 135 void TestCrashingChild(const base::string16& directory_modification) {
140 size_t length = 0;
141 EXPECT_TRUE(LoggingReadFile(handle, &length, sizeof(length)));
142 scoped_ptr<char[]> buffer(new char[length]);
143 EXPECT_TRUE(LoggingReadFile(handle, &buffer[0], length));
144 return std::string(&buffer[0], length);
145 }
146
147 void WriteString(FileHandle handle, const std::string& str) {
148 size_t length = str.size();
149 EXPECT_TRUE(LoggingWriteFile(handle, &length, sizeof(length)));
150 EXPECT_TRUE(LoggingWriteFile(handle, &str[0], length));
151 }
152
153 __declspec(noinline) void* CurrentAddress() {
154 return _ReturnAddress();
155 }
156
157 class CrashingChildProcess final : public WinChildProcess {
158 public:
159 CrashingChildProcess() : WinChildProcess() {}
160 ~CrashingChildProcess() {}
161
162 private:
163 int Run() override {
164 std::string pipe_name = ReadString(ReadPipeHandle());
165 CrashpadClient client;
166 EXPECT_TRUE(client.SetHandler(pipe_name));
167 EXPECT_TRUE(client.UseHandler());
168 // Save the address where we're about to crash so the exception handler can
169 // verify it's in approximately the right location (with a bit of fudge for
170 // the code between here and the __debugbreak()).
171 void* break_address = CurrentAddress();
172 LoggingWriteFile(WritePipeHandle(), &break_address, sizeof(break_address));
173 __debugbreak();
174 return 0;
175 };
176 };
177
178 TEST_F(ExceptionSnapshotWinTest, ChildCrash) {
179 // Spawn a child process that will immediately crash (once we let it
180 // run below by telling it what to connect to).
181 WinChildProcess::EntryPoint<CrashingChildProcess>();
182 scoped_ptr<WinChildProcess::Handles> handle = WinChildProcess::Launch();
183
184 // Set up the registration server on a background thread. 136 // Set up the registration server on a background thread.
185 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" + 137 std::string pipe_name = "\\\\.\\pipe\\handler_test_pipe_" +
186 base::StringPrintf("%08x", GetCurrentProcessId()); 138 base::StringPrintf("%08x", GetCurrentProcessId());
187 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); 139 ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
188 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr)); 140 ScopedKernelHANDLE completed(CreateEvent(nullptr, false, false, nullptr));
189 Delegate delegate(server_ready.get(), completed.get()); 141 Delegate delegate(server_ready.get(), completed.get());
190 142
191 ExceptionHandlerServer exception_handler_server; 143 ExceptionHandlerServer exception_handler_server;
192 RunServerThread server_thread( 144 RunServerThread server_thread(
193 &exception_handler_server, &delegate, pipe_name); 145 &exception_handler_server, &delegate, pipe_name);
194 server_thread.Start(); 146 server_thread.Start();
195 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( 147 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
196 &exception_handler_server, &server_thread); 148 &exception_handler_server, &server_thread);
197 149
198 WaitForSingleObject(server_ready.get(), INFINITE); 150 WaitForSingleObject(server_ready.get(), INFINITE);
199 // Allow the child to continue and tell it where to connect to. 151
200 WriteString(handle->write.get(), pipe_name); 152 // Spawn a child process, passing it the pipe name to connect to.
153 base::FilePath test_executable = Paths::Executable();
154 std::wstring child_test_executable =
155 test_executable.DirName()
156 .Append(directory_modification)
157 .Append(test_executable.BaseName().RemoveFinalExtension().value() +
158 L"_crashing_child.exe")
159 .value();
160
161 // Create a pipe for the stdout of the child.
162 SECURITY_ATTRIBUTES security_attributes = {0};
163 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
164 security_attributes.bInheritHandle = true;
165 HANDLE stdout_read;
166 HANDLE stdout_write;
167 ASSERT_TRUE(CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0));
168 ScopedFileHANDLE read_handle(stdout_read);
169 ScopedFileHANDLE write_handle(stdout_write);
170 ASSERT_TRUE(SetHandleInformation(read_handle.get(), HANDLE_FLAG_INHERIT, 0));
171
172 std::wstring command_line =
173 child_test_executable + L" " + base::UTF8ToUTF16(pipe_name);
174 STARTUPINFO startup_info = {0};
175 startup_info.cb = sizeof(startup_info);
176 startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
177 startup_info.hStdOutput = write_handle.get();
178 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
179 startup_info.dwFlags = STARTF_USESTDHANDLES;
180 PROCESS_INFORMATION process_information;
181 ASSERT_TRUE(CreateProcess(child_test_executable.c_str(),
182 &command_line[0],
183 nullptr,
184 nullptr,
185 true,
186 0,
187 nullptr,
188 nullptr,
189 &startup_info,
190 &process_information));
191 // Take ownership of the two process handles returned.
192 ScopedKernelHANDLE process_main_thread_handle(process_information.hThread);
193 ScopedKernelHANDLE process_handle(process_information.hProcess);
201 194
202 // The child tells us (approximately) where it will crash. 195 // The child tells us (approximately) where it will crash.
203 void* break_near_address; 196 WinVMAddress break_near_address;
204 LoggingReadFile( 197 LoggingReadFile(
205 handle->read.get(), &break_near_address, sizeof(break_near_address)); 198 read_handle.get(), &break_near_address, sizeof(break_near_address));
206 delegate.set_break_near(break_near_address); 199 delegate.set_break_near(break_near_address);
207 200
208 // Wait for the child to crash and the exception information to be validated. 201 // Wait for the child to crash and the exception information to be validated.
209 WaitForSingleObject(completed.get(), INFINITE); 202 WaitForSingleObject(completed.get(), INFINITE);
210 } 203 }
211 204
205 TEST(ExceptionSnapshotWinTest, ChildCrash) {
206 TestCrashingChild(FILE_PATH_LITERAL("."));
207 }
208
209 #if defined(ARCH_CPU_64_BITS)
210 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) {
211 #ifndef NDEBUG
212 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Debug"));
213 #else
214 TestCrashingChild(FILE_PATH_LITERAL("..\\..\\out\\Release"));
215 #endif
216 }
217 #endif // ARCH_CPU_64_BITS
218
212 } // namespace 219 } // namespace
213 } // namespace test 220 } // namespace test
214 } // namespace crashpad 221 } // namespace crashpad
OLDNEW
« no previous file with comments | « snapshot/win/exception_snapshot_win.cc ('k') | snapshot/win/process_reader_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698