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

Side by Side Diff: client/crashpad_client_win.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 | « client/client.gyp ('k') | client/registration_protocol_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 "client/crashpad_client.h" 15 #include "client/crashpad_client.h"
16 16
17 #include <string.h>
17 #include <windows.h> 18 #include <windows.h>
18 19
19 #include "base/atomicops.h" 20 #include "base/atomicops.h"
20 #include "base/logging.h" 21 #include "base/logging.h"
21 #include "base/strings/string16.h" 22 #include "base/strings/string16.h"
22 #include "base/strings/utf_string_conversions.h" 23 #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" 24 #include "util/file/file_io.h"
25 #include "util/win/registration_protocol_win.h"
26 #include "util/win/scoped_handle.h" 26 #include "util/win/scoped_handle.h"
27 27
28 namespace { 28 namespace {
29 // Time to wait for the handler to create a dump. This is tricky to figure out.
30 const DWORD kMillisecondsUntilTerminate = 5000;
31 29
32 // This is the exit code that the process will return to the system once the 30 // This handle is never closed.
33 // crash has been handled by Crashpad. We don't want to clash with the 31 HANDLE g_signal_exception = INVALID_HANDLE_VALUE;
34 // application-defined exit codes but we don't know them so we use one that is
35 // unlikely to be used.
36 const UINT kCrashExitCode = 0xffff7001;
37 32
38 // These two handles to events are leaked. 33 // Where we store the exception information that the crash handler reads.
39 HANDLE g_signal_exception = nullptr; 34 crashpad::ExceptionInformation g_exception_information;
40 HANDLE g_wait_termination = nullptr;
41
42 // Tracks whether a thread has already entered UnhandledExceptionHandler.
43 base::subtle::AtomicWord g_have_crashed;
44 35
45 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { 36 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
37 // Tracks whether a thread has already entered UnhandledExceptionHandler.
38 static base::subtle::AtomicWord have_crashed;
39
46 // This is a per-process handler. While this handler is being invoked, other 40 // 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 41 // 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 42 // 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 43 // 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 44 // 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 45 // the global exception pointers in ExceptionInformation. Because the crash
52 // will record all threads, it's fine to simply have the second and subsequent 46 // handler will record all threads, it's fine to simply have the second and
53 // entrants block here. They will soon be suspended by the crash handler, and 47 // subsequent entrants block here. They will soon be suspended by the crash
54 // then the entire process will be terminated below. This means that we won't 48 // handler, and then the entire process will be terminated below. This means
55 // save the exception pointers from the second and further crashes, but 49 // that we won't save the exception pointers from the second and further
56 // contention here is very unlikely, and we'll still have a stack that's 50 // crashes, but contention here is very unlikely, and we'll still have a stack
57 // blocked at this location. 51 // that's blocked at this location.
58 if (base::subtle::Barrier_AtomicIncrement(&g_have_crashed, 1) > 1) { 52 if (base::subtle::Barrier_AtomicIncrement(&have_crashed, 1) > 1) {
59 SleepEx(INFINITE, false); 53 SleepEx(INFINITE, false);
60 } 54 }
61 55
62 // Otherwise, we're the first thread, so record the exception pointer and 56 // Otherwise, we're the first thread, so record the exception pointer and
63 // signal the crash handler. 57 // signal the crash handler.
64 crashpad::CrashpadInfo::GetCrashpadInfo()->set_thread_id( 58 g_exception_information.thread_id = GetCurrentThreadId();
65 GetCurrentThreadId()); 59 g_exception_information.exception_pointers =
66 crashpad::CrashpadInfo::GetCrashpadInfo()->set_exception_pointers( 60 reinterpret_cast<crashpad::WinVMAddress>(exception_pointers);
67 exception_pointers);
68 DWORD rv = SignalObjectAndWait(g_signal_exception,
69 g_wait_termination,
70 kMillisecondsUntilTerminate,
71 false);
72 if (rv != WAIT_OBJECT_0) {
73 // Something went wrong. It is likely that a dump has not been created.
74 if (rv == WAIT_TIMEOUT) {
75 LOG(WARNING) << "SignalObjectAndWait timed out";
76 } else {
77 PLOG(WARNING) << "SignalObjectAndWait error";
78 }
79 }
80 // We don't want to generate more exceptions, so we take the fast route.
81 TerminateProcess(GetCurrentProcess(), kCrashExitCode);
82 return 0L;
83 }
84 61
85 // Returns a pipe handle connected to the RegistrationServer. 62 // Now signal the crash server, which will take a dump and then terminate us
86 crashpad::ScopedFileHANDLE Connect(const base::string16& pipe_name) { 63 // when it's complete.
87 crashpad::ScopedFileHANDLE pipe; 64 SetEvent(g_signal_exception);
88 const int kMaxTries = 5;
89 for (int tries = 0; tries < kMaxTries; ++tries) {
90 pipe.reset(CreateFile(pipe_name.c_str(),
91 GENERIC_READ | GENERIC_WRITE,
92 0,
93 nullptr,
94 OPEN_EXISTING,
95 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
96 nullptr));
97 if (pipe.is_valid())
98 break;
99 65
100 // If busy, wait 60s before retrying. 66 // Time to wait for the handler to create a dump.
101 if (GetLastError() != ERROR_PIPE_BUSY) { 67 const DWORD kMillisecondsUntilTerminate = 60 * 1000;
102 PLOG(ERROR) << "CreateFile pipe connection";
103 return crashpad::ScopedFileHANDLE();
104 } else if (!WaitNamedPipe(pipe_name.c_str(), 60000)) {
105 PLOG(ERROR) << "WaitNamedPipe";
106 }
107 }
108 68
109 if (!pipe.is_valid()) 69 // Sleep for a while to allow it to process us. Eventually, we terminate
110 return crashpad::ScopedFileHANDLE(); 70 // ourselves in case the crash server is gone, so that we don't leave zombies
71 // around. This would ideally never happen.
72 // TODO(scottmg): Re-add the "reply" event here, for implementing
73 // DumpWithoutCrashing.
74 Sleep(kMillisecondsUntilTerminate);
111 75
112 DWORD mode = PIPE_READMODE_MESSAGE; 76 LOG(ERROR) << "crash server did not respond, self-terminating";
113 if (!SetNamedPipeHandleState(pipe.get(),
114 &mode,
115 nullptr, // Don't set maximum bytes.
116 nullptr)) { // Don't set maximum time.
117 PLOG(ERROR) << "SetNamedPipeHandleState";
118 return crashpad::ScopedFileHANDLE();
119 }
120 77
121 return pipe.Pass(); 78 const UINT kCrashExitCodeNoDump = 0xffff7001;
79 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump);
80
81 return EXCEPTION_CONTINUE_SEARCH;
122 } 82 }
123 83
124 } // namespace 84 } // namespace
125 85
126 namespace crashpad { 86 namespace crashpad {
127 87
128 CrashpadClient::CrashpadClient() { 88 CrashpadClient::CrashpadClient() {
129 } 89 }
130 90
131 CrashpadClient::~CrashpadClient() { 91 CrashpadClient::~CrashpadClient() {
132 } 92 }
133 93
134 bool CrashpadClient::StartHandler( 94 bool CrashpadClient::StartHandler(
135 const base::FilePath& handler, 95 const base::FilePath& handler,
136 const base::FilePath& database, 96 const base::FilePath& database,
137 const std::string& url, 97 const std::string& url,
138 const std::map<std::string, std::string>& annotations, 98 const std::map<std::string, std::string>& annotations,
139 const std::vector<std::string>& arguments) { 99 const std::vector<std::string>& arguments) {
100 LOG(FATAL) << "SetHandler should be used on Windows";
140 return false; 101 return false;
141 } 102 }
142 103
143 bool CrashpadClient::SetHandler(const std::string& ipc_port) { 104 bool CrashpadClient::SetHandler(const std::string& ipc_port) {
144 RegistrationRequest request = {0}; 105 ClientToServerMessage message;
145 request.client_process_id = GetCurrentProcessId(); 106 memset(&message, 0, sizeof(message));
146 request.crashpad_info_address = 107 message.type = ClientToServerMessage::kRegister;
147 reinterpret_cast<WinVMAddress>(CrashpadInfo::GetCrashpadInfo()); 108 message.registration.client_process_id = GetCurrentProcessId();
109 message.registration.exception_information =
110 reinterpret_cast<WinVMAddress>(&g_exception_information);
148 111
149 RegistrationResponse response = {0}; 112 ServerToClientMessage response = {0};
150 113
151 ScopedFileHANDLE pipe = Connect(base::UTF8ToUTF16(ipc_port)); 114 if (!SendToCrashHandlerServer(
152 if (!pipe.is_valid()) 115 base::UTF8ToUTF16(ipc_port), message, &response)) {
153 return false; 116 return false;
154 bool result = LoggingWriteFile(pipe.get(), &request, sizeof(request)) && 117 }
155 LoggingReadFile(pipe.get(), &response, sizeof(response));
156 if (!result)
157 return result;
158 118
159 // The server returns these already duplicated to be valid in this process. 119 // The server returns these already duplicated to be valid in this process.
160 g_signal_exception = reinterpret_cast<HANDLE>(response.request_report_event); 120 g_signal_exception =
161 g_wait_termination = 121 reinterpret_cast<HANDLE>(response.registration.request_report_event);
162 reinterpret_cast<HANDLE>(response.report_complete_event);
163 return true; 122 return true;
164 } 123 }
165 124
166 bool CrashpadClient::UseHandler() { 125 bool CrashpadClient::UseHandler() {
167 if (!g_signal_exception) 126 if (g_signal_exception == INVALID_HANDLE_VALUE)
168 return false;
169 if (!g_wait_termination)
170 return false; 127 return false;
171 // In theory we could store the previous handler but it is not clear what 128 // In theory we could store the previous handler but it is not clear what
172 // use we have for it. 129 // use we have for it.
173 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); 130 SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
174 return true; 131 return true;
175 } 132 }
176 133
177 } // namespace crashpad 134 } // namespace crashpad
OLDNEW
« no previous file with comments | « client/client.gyp ('k') | client/registration_protocol_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698