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

Side by Side Diff: client/crashpad_client_win.cc

Issue 1287073002: Implement more of CrashpadClient on Windows (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: fixes 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 | « client/crashpad_client_mac.cc ('k') | client/crashpad_info.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 "client/crashpad_client.h" 15 #include "client/crashpad_client.h"
16 16
17 #include <windows.h> 17 #include <windows.h>
18 18
19 #include "base/atomicops.h"
19 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/strings/string16.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "client/crashpad_info.h"
24 #include "client/registration_protocol_win.h"
25 #include "util/file/file_io.h"
26 #include "util/win/scoped_handle.h"
20 27
21 namespace { 28 namespace {
22 // Time to wait for the handler to create a dump. This is tricky to figure out. 29 // Time to wait for the handler to create a dump. This is tricky to figure out.
23 const DWORD kMillisecondsUntilTerminate = 5000; 30 const DWORD kMillisecondsUntilTerminate = 5000;
24 31
25 // This is the exit code that the process will return to the system once the 32 // This is the exit code that the process will return to the system once the
26 // crash has been handled by Crashpad. We don't want to clash with the 33 // crash has been handled by Crashpad. We don't want to clash with the
27 // application-defined exit codes but we don't know them so we use one that is 34 // application-defined exit codes but we don't know them so we use one that is
28 // unlikely to be used. 35 // unlikely to be used.
29 const UINT kCrashExitCode = 0xffff7001; 36 const UINT kCrashExitCode = 0xffff7001;
30 37
31 // These two handles to events are leaked. 38 // These two handles to events are leaked.
32 HANDLE g_signal_exception = nullptr; 39 HANDLE g_signal_exception = nullptr;
33 HANDLE g_wait_termination = nullptr; 40 HANDLE g_wait_termination = nullptr;
34 41
42 // Tracks whether a thread has already entered UnhandledExceptionHandler.
43 base::subtle::AtomicWord g_have_crashed;
44
35 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { 45 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
36 // TODO (cpu): Here write |exception_pointers| to g_crashpad_info. 46 // This is a per-process handler. While this handler is being invoked, other
47 // threads are still executing as usual, so multiple threads could enter at
48 // the same time. Because we're in a crashing state, we shouldn't be doing
49 // anything that might cause allocations, call into kernel mode, etc. So, we
50 // don't want to take a critical section here to avoid simultaneous access to
51 // the global exception pointers in CrashpadInfo. Because the crash handler
52 // will record all threads, it's fine to simply have the second and subsequent
53 // entrants block here. They will soon be suspended by the crash handler, and
54 // then the entire process will be terminated below. This means that we won't
55 // the exception pointers from the second and further crashes, but contention
Mark Mentovai 2015/08/14 14:20:54 Missing a word.
scottmg 2015/08/14 21:13:21 Done.
56 // here is very unlikely, and we'll still have a stack that's blocked at this
57 // location.
cpu_(ooo_6.6-7.5) 2015/08/14 00:47:13 yeah, it would be nice to know the count of thread
scottmg 2015/08/14 21:13:21 We could alias the count to the stack, but since i
58 if (base::subtle::Barrier_AtomicIncrement(&g_have_crashed, 1) > 1) {
59 SleepEx(false, INFINITE);
60 }
61
62 // Otherwise, we're the first thread, so record the exception pointer and
63 // signal the crash handler.
64 crashpad::CrashpadInfo::GetCrashpadInfo()->set_exception_pointers(
65 exception_pointers);
37 DWORD rv = SignalObjectAndWait(g_signal_exception, 66 DWORD rv = SignalObjectAndWait(g_signal_exception,
38 g_wait_termination, 67 g_wait_termination,
39 kMillisecondsUntilTerminate, 68 kMillisecondsUntilTerminate,
40 FALSE); 69 FALSE);
41 if (rv != WAIT_OBJECT_0) { 70 if (rv != WAIT_OBJECT_0) {
42 // Something went wrong. It is likely that a dump has not been created. 71 // Something went wrong. It is likely that a dump has not been created.
43 if (rv == WAIT_TIMEOUT) { 72 if (rv == WAIT_TIMEOUT) {
44 LOG(WARNING) << "SignalObjectAndWait timed out"; 73 LOG(WARNING) << "SignalObjectAndWait timed out";
45 } else { 74 } else {
46 PLOG(WARNING) << "SignalObjectAndWait error"; 75 PLOG(WARNING) << "SignalObjectAndWait error";
47 } 76 }
48 } 77 }
49 // We don't want to generate more exceptions, so we take the fast route. 78 // We don't want to generate more exceptions, so we take the fast route.
50 TerminateProcess(GetCurrentProcess(), kCrashExitCode); 79 TerminateProcess(GetCurrentProcess(), kCrashExitCode);
51 return 0L; 80 return 0L;
52 } 81 }
53 82
83 // Returns a pipe handle connected to the RegistrationServer.
84 crashpad::ScopedFileHANDLE Connect(const base::string16& pipe_name) {
85 crashpad::ScopedFileHANDLE pipe;
86 const int kMaxTries = 5;
87 for (int tries = 0; !pipe.is_valid() && tries < kMaxTries; ++tries) {
88 if (!WaitNamedPipe(pipe_name.c_str(), NMPWAIT_WAIT_FOREVER)) {
89 PLOG(ERROR) << "WaitNamedPipe";
cpu_(ooo_6.6-7.5) 2015/08/14 00:47:13 WaitNamedPipe internally tries to open the NPFS de
scottmg 2015/08/14 21:13:21 Thanks, switched to a 60s timeout and tried openin
90 }
91 pipe.reset(CreateFile(pipe_name.c_str(),
Mark Mentovai 2015/08/14 14:20:54 So regardless of whether WaitNamedPipe() succeeds,
scottmg 2015/08/14 21:13:21 Done.
92 GENERIC_READ | GENERIC_WRITE,
93 0,
94 nullptr,
95 OPEN_EXISTING,
96 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
97 nullptr));
98 if (!pipe.is_valid()) {
99 PLOG(ERROR) << "CreateFile pipe connection";
100 } else {
101 DWORD mode = PIPE_READMODE_MESSAGE;
102 if (!SetNamedPipeHandleState(pipe.get(),
103 &mode,
104 nullptr, // Don't set maximum bytes.
105 nullptr)) { // Don't set maximum time.
106 PLOG(ERROR) << "SetNamedPipeHandleState";
107 pipe.reset();
108 }
109 }
110 }
111 if (!pipe.is_valid())
112 return crashpad::ScopedFileHANDLE();
113 return pipe.Pass();
114 }
115
54 } // namespace 116 } // namespace
55 117
56 namespace crashpad { 118 namespace crashpad {
57 119
58 CrashpadClient::CrashpadClient() { 120 CrashpadClient::CrashpadClient() {
59 } 121 }
60 122
61 CrashpadClient::~CrashpadClient() { 123 CrashpadClient::~CrashpadClient() {
62 } 124 }
63 125
64 bool CrashpadClient::StartHandler( 126 bool CrashpadClient::StartHandler(
65 const base::FilePath& handler, 127 const base::FilePath& handler,
66 const base::FilePath& database, 128 const base::FilePath& database,
67 const std::string& url, 129 const std::string& url,
68 const std::map<std::string, std::string>& annotations, 130 const std::map<std::string, std::string>& annotations,
69 const std::vector<std::string>& arguments) { 131 const std::vector<std::string>& arguments) {
70 // TODO(cpu): Provide a reference implementation.
71 return false; 132 return false;
72 } 133 }
73 134
74 bool CrashpadClient::SetHandler(const std::string& ipc_port) { 135 bool CrashpadClient::SetHandler(const std::string& ipc_port) {
75 // TODO (cpu): Contact the handler and obtain g_signal_exception and 136 RegistrationRequest request = {0};
76 // g_wait_termination. 137 request.client_process_id = GetCurrentProcessId();
77 return false; 138 request.crashpad_info_address =
139 reinterpret_cast<WinVMAddress>(CrashpadInfo::GetCrashpadInfo());
140
141 RegistrationResponse response = {0};
142
143 ScopedFileHANDLE pipe = Connect(base::UTF8ToUTF16(ipc_port));
144 if (!pipe.is_valid())
145 return false;
146 bool result = LoggingWriteFile(pipe.get(), &request, sizeof(request)) &&
147 LoggingReadFile(pipe.get(), &response, sizeof(response));
cpu_(ooo_6.6-7.5) 2015/08/14 00:47:13 TransactNamedPipe is available if you want to, but
scottmg 2015/08/14 21:13:21 I think I'll stick with Write+Read since it has lo
148 if (!result)
149 return result;
150
151 // The server returns these already duplicated to be valid in this process.
152 g_signal_exception = reinterpret_cast<HANDLE>(response.request_report_event);
153 g_wait_termination =
154 reinterpret_cast<HANDLE>(response.report_complete_event);
155 return true;
78 } 156 }
79 157
80 bool CrashpadClient::UseHandler() { 158 bool CrashpadClient::UseHandler() {
81 if (!g_signal_exception) 159 if (!g_signal_exception)
82 return false; 160 return false;
83 if (!g_wait_termination) 161 if (!g_wait_termination)
84 return false; 162 return false;
85 // In theory we could store the previous handler but it is not clear what 163 // In theory we could store the previous handler but it is not clear what
86 // use we have for it. 164 // use we have for it.
87 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); 165 SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
88 return true; 166 return true;
89 } 167 }
90 168
91 } // namespace crashpad 169 } // namespace crashpad
OLDNEW
« no previous file with comments | « client/crashpad_client_mac.cc ('k') | client/crashpad_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698