OLD | NEW |
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 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 //! \brief The context data for registered threadpool waits. | 96 //! \brief The context data for registered threadpool waits. |
97 //! | 97 //! |
98 //! This object must be created and destroyed on the main thread. Access must be | 98 //! This object must be created and destroyed on the main thread. Access must be |
99 //! guarded by use of the lock() with the exception of the threadpool wait | 99 //! guarded by use of the lock() with the exception of the threadpool wait |
100 //! variables which are accessed only by the main thread. | 100 //! variables which are accessed only by the main thread. |
101 class ClientData { | 101 class ClientData { |
102 public: | 102 public: |
103 ClientData(HANDLE port, | 103 ClientData(HANDLE port, |
104 ExceptionHandlerServer::Delegate* delegate, | 104 ExceptionHandlerServer::Delegate* delegate, |
105 ScopedKernelHANDLE process, | 105 ScopedKernelHANDLE process, |
106 WinVMAddress exception_information_address, | 106 WinVMAddress crash_exception_information_address, |
107 WAITORTIMERCALLBACK dump_request_callback, | 107 WinVMAddress non_crash_exception_information_address, |
| 108 WAITORTIMERCALLBACK crash_dump_request_callback, |
| 109 WAITORTIMERCALLBACK non_crash_dump_request_callback, |
108 WAITORTIMERCALLBACK process_end_callback) | 110 WAITORTIMERCALLBACK process_end_callback) |
109 : dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), | 111 : crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), |
| 112 non_crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), |
110 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), | 113 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), |
111 lock_(), | 114 lock_(), |
112 port_(port), | 115 port_(port), |
113 delegate_(delegate), | 116 delegate_(delegate), |
114 dump_requested_event_( | 117 crash_dump_requested_event_( |
| 118 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
| 119 non_crash_dump_requested_event_( |
| 120 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
| 121 non_crash_dump_completed_event_( |
115 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | 122 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
116 process_(process.Pass()), | 123 process_(process.Pass()), |
117 exception_information_address_(exception_information_address) { | 124 crash_exception_information_address_( |
118 RegisterThreadPoolWaits(dump_request_callback, process_end_callback); | 125 crash_exception_information_address), |
| 126 non_crash_exception_information_address_( |
| 127 non_crash_exception_information_address) { |
| 128 RegisterThreadPoolWaits(crash_dump_request_callback, |
| 129 non_crash_dump_request_callback, |
| 130 process_end_callback); |
119 } | 131 } |
120 | 132 |
121 ~ClientData() { | 133 ~ClientData() { |
122 // It is important that this only access the threadpool waits (it's called | 134 // It is important that this only access the threadpool waits (it's called |
123 // from the main thread) until the waits are unregistered, to ensure that | 135 // from the main thread) until the waits are unregistered, to ensure that |
124 // any outstanding callbacks are complete. | 136 // any outstanding callbacks are complete. |
125 UnregisterThreadPoolWaits(); | 137 UnregisterThreadPoolWaits(); |
126 } | 138 } |
127 | 139 |
128 base::Lock* lock() { return &lock_; } | 140 base::Lock* lock() { return &lock_; } |
129 HANDLE port() const { return port_; } | 141 HANDLE port() const { return port_; } |
130 ExceptionHandlerServer::Delegate* delegate() const { return delegate_; } | 142 ExceptionHandlerServer::Delegate* delegate() const { return delegate_; } |
131 HANDLE dump_requested_event() const { return dump_requested_event_.get(); } | 143 HANDLE crash_dump_requested_event() const { |
132 WinVMAddress exception_information_address() const { | 144 return crash_dump_requested_event_.get(); |
133 return exception_information_address_; | 145 } |
| 146 HANDLE non_crash_dump_requested_event() const { |
| 147 return non_crash_dump_requested_event_.get(); |
| 148 } |
| 149 HANDLE non_crash_dump_completed_event() const { |
| 150 return non_crash_dump_completed_event_.get(); |
| 151 } |
| 152 WinVMAddress crash_exception_information_address() const { |
| 153 return crash_exception_information_address_; |
| 154 } |
| 155 WinVMAddress non_crash_exception_information_address() const { |
| 156 return non_crash_exception_information_address_; |
134 } | 157 } |
135 HANDLE process() const { return process_.get(); } | 158 HANDLE process() const { return process_.get(); } |
136 | 159 |
137 private: | 160 private: |
138 void RegisterThreadPoolWaits(WAITORTIMERCALLBACK dump_request_callback, | 161 void RegisterThreadPoolWaits( |
139 WAITORTIMERCALLBACK process_end_callback) { | 162 WAITORTIMERCALLBACK crash_dump_request_callback, |
140 if (!RegisterWaitForSingleObject(&dump_request_thread_pool_wait_, | 163 WAITORTIMERCALLBACK non_crash_dump_request_callback, |
141 dump_requested_event_.get(), | 164 WAITORTIMERCALLBACK process_end_callback) { |
142 dump_request_callback, | 165 if (!RegisterWaitForSingleObject(&crash_dump_request_thread_pool_wait_, |
| 166 crash_dump_requested_event_.get(), |
| 167 crash_dump_request_callback, |
143 this, | 168 this, |
144 INFINITE, | 169 INFINITE, |
145 WT_EXECUTEDEFAULT)) { | 170 WT_EXECUTEDEFAULT)) { |
146 LOG(ERROR) << "RegisterWaitForSingleObject dump requested"; | 171 LOG(ERROR) << "RegisterWaitForSingleObject crash dump requested"; |
| 172 } |
| 173 |
| 174 if (!RegisterWaitForSingleObject(&non_crash_dump_request_thread_pool_wait_, |
| 175 non_crash_dump_requested_event_.get(), |
| 176 non_crash_dump_request_callback, |
| 177 this, |
| 178 INFINITE, |
| 179 WT_EXECUTEDEFAULT)) { |
| 180 LOG(ERROR) << "RegisterWaitForSingleObject non-crash dump requested"; |
147 } | 181 } |
148 | 182 |
149 if (!RegisterWaitForSingleObject(&process_end_thread_pool_wait_, | 183 if (!RegisterWaitForSingleObject(&process_end_thread_pool_wait_, |
150 process_.get(), | 184 process_.get(), |
151 process_end_callback, | 185 process_end_callback, |
152 this, | 186 this, |
153 INFINITE, | 187 INFINITE, |
154 WT_EXECUTEONLYONCE)) { | 188 WT_EXECUTEONLYONCE)) { |
155 LOG(ERROR) << "RegisterWaitForSingleObject process end"; | 189 LOG(ERROR) << "RegisterWaitForSingleObject process end"; |
156 } | 190 } |
157 } | 191 } |
158 | 192 |
159 // This blocks until outstanding calls complete so that we know it's safe to | 193 // This blocks until outstanding calls complete so that we know it's safe to |
160 // delete this object. Because of this, it must be executed on the main | 194 // delete this object. Because of this, it must be executed on the main |
161 // thread, not a threadpool thread. | 195 // thread, not a threadpool thread. |
162 void UnregisterThreadPoolWaits() { | 196 void UnregisterThreadPoolWaits() { |
163 UnregisterWaitEx(dump_request_thread_pool_wait_, INVALID_HANDLE_VALUE); | 197 UnregisterWaitEx(crash_dump_request_thread_pool_wait_, |
164 dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; | 198 INVALID_HANDLE_VALUE); |
| 199 crash_dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; |
| 200 UnregisterWaitEx(non_crash_dump_request_thread_pool_wait_, |
| 201 INVALID_HANDLE_VALUE); |
| 202 non_crash_dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; |
165 UnregisterWaitEx(process_end_thread_pool_wait_, INVALID_HANDLE_VALUE); | 203 UnregisterWaitEx(process_end_thread_pool_wait_, INVALID_HANDLE_VALUE); |
166 process_end_thread_pool_wait_ = INVALID_HANDLE_VALUE; | 204 process_end_thread_pool_wait_ = INVALID_HANDLE_VALUE; |
167 } | 205 } |
168 | 206 |
169 // These are only accessed on the main thread. | 207 // These are only accessed on the main thread. |
170 HANDLE dump_request_thread_pool_wait_; | 208 HANDLE crash_dump_request_thread_pool_wait_; |
| 209 HANDLE non_crash_dump_request_thread_pool_wait_; |
171 HANDLE process_end_thread_pool_wait_; | 210 HANDLE process_end_thread_pool_wait_; |
172 | 211 |
173 base::Lock lock_; | 212 base::Lock lock_; |
174 // Access to these fields must be guarded by lock_. | 213 // Access to these fields must be guarded by lock_. |
175 HANDLE port_; // weak | 214 HANDLE port_; // weak |
176 ExceptionHandlerServer::Delegate* delegate_; // weak | 215 ExceptionHandlerServer::Delegate* delegate_; // weak |
177 ScopedKernelHANDLE dump_requested_event_; | 216 ScopedKernelHANDLE crash_dump_requested_event_; |
| 217 ScopedKernelHANDLE non_crash_dump_requested_event_; |
| 218 ScopedKernelHANDLE non_crash_dump_completed_event_; |
178 ScopedKernelHANDLE process_; | 219 ScopedKernelHANDLE process_; |
179 WinVMAddress exception_information_address_; | 220 WinVMAddress crash_exception_information_address_; |
| 221 WinVMAddress non_crash_exception_information_address_; |
180 | 222 |
181 DISALLOW_COPY_AND_ASSIGN(ClientData); | 223 DISALLOW_COPY_AND_ASSIGN(ClientData); |
182 }; | 224 }; |
183 | 225 |
184 } // namespace internal | 226 } // namespace internal |
185 | 227 |
186 ExceptionHandlerServer::Delegate::~Delegate() { | 228 ExceptionHandlerServer::Delegate::~Delegate() { |
187 } | 229 } |
188 | 230 |
189 ExceptionHandlerServer::ExceptionHandlerServer() | 231 ExceptionHandlerServer::ExceptionHandlerServer() |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 PCHECK(RevertToSelf()); | 399 PCHECK(RevertToSelf()); |
358 if (!client_process) { | 400 if (!client_process) { |
359 LOG(ERROR) << "failed to open " << message.registration.client_process_id; | 401 LOG(ERROR) << "failed to open " << message.registration.client_process_id; |
360 return false; | 402 return false; |
361 } | 403 } |
362 } | 404 } |
363 | 405 |
364 internal::ClientData* client; | 406 internal::ClientData* client; |
365 { | 407 { |
366 base::AutoLock lock(*service_context.clients_lock()); | 408 base::AutoLock lock(*service_context.clients_lock()); |
367 client = | 409 client = new internal::ClientData( |
368 new internal::ClientData(service_context.port(), | 410 service_context.port(), |
369 service_context.delegate(), | 411 service_context.delegate(), |
370 ScopedKernelHANDLE(client_process), | 412 ScopedKernelHANDLE(client_process), |
371 message.registration.exception_information, | 413 message.registration.crash_exception_information, |
372 &OnDumpEvent, | 414 message.registration.non_crash_exception_information, |
373 &OnProcessEnd); | 415 &OnCrashDumpEvent, |
| 416 &OnNonCrashDumpEvent, |
| 417 &OnProcessEnd); |
374 service_context.clients()->insert(client); | 418 service_context.clients()->insert(client); |
375 } | 419 } |
376 | 420 |
377 // Duplicate the events back to the client so they can request a dump. | 421 // Duplicate the events back to the client so they can request a dump. |
378 ServerToClientMessage response; | 422 ServerToClientMessage response; |
379 response.registration.request_report_event = | 423 response.registration.request_crash_dump_event = |
380 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>( | 424 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( |
381 DuplicateEvent(client->process(), client->dump_requested_event()))); | 425 client->process(), client->crash_dump_requested_event()))); |
| 426 response.registration.request_non_crash_dump_event = |
| 427 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( |
| 428 client->process(), client->non_crash_dump_requested_event()))); |
| 429 response.registration.non_crash_dump_completed_event = |
| 430 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( |
| 431 client->process(), client->non_crash_dump_completed_event()))); |
382 | 432 |
383 if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) | 433 if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) |
384 return false; | 434 return false; |
385 | 435 |
386 return false; | 436 return false; |
387 } | 437 } |
388 | 438 |
389 // static | 439 // static |
390 DWORD __stdcall ExceptionHandlerServer::PipeServiceProc(void* ctx) { | 440 DWORD __stdcall ExceptionHandlerServer::PipeServiceProc(void* ctx) { |
391 internal::PipeServiceContext* service_context = | 441 internal::PipeServiceContext* service_context = |
392 reinterpret_cast<internal::PipeServiceContext*>(ctx); | 442 reinterpret_cast<internal::PipeServiceContext*>(ctx); |
393 DCHECK(service_context); | 443 DCHECK(service_context); |
394 | 444 |
395 for (;;) { | 445 for (;;) { |
396 bool ret = ConnectNamedPipe(service_context->pipe(), nullptr); | 446 bool ret = ConnectNamedPipe(service_context->pipe(), nullptr); |
397 if (!ret && GetLastError() != ERROR_PIPE_CONNECTED) { | 447 if (!ret && GetLastError() != ERROR_PIPE_CONNECTED) { |
398 PLOG(ERROR) << "ConnectNamedPipe"; | 448 PLOG(ERROR) << "ConnectNamedPipe"; |
399 } else if (ServiceClientConnection(*service_context)) { | 449 } else if (ServiceClientConnection(*service_context)) { |
400 break; | 450 break; |
401 } | 451 } |
402 DisconnectNamedPipe(service_context->pipe()); | 452 DisconnectNamedPipe(service_context->pipe()); |
403 } | 453 } |
404 | 454 |
405 delete service_context; | 455 delete service_context; |
406 | 456 |
407 return 0; | 457 return 0; |
408 } | 458 } |
409 | 459 |
410 // static | 460 // static |
411 void __stdcall ExceptionHandlerServer::OnDumpEvent(void* ctx, BOOLEAN) { | 461 void __stdcall ExceptionHandlerServer::OnCrashDumpEvent(void* ctx, BOOLEAN) { |
412 // This function is executed on the thread pool. | 462 // This function is executed on the thread pool. |
413 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 463 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
414 base::AutoLock lock(*client->lock()); | 464 base::AutoLock lock(*client->lock()); |
415 | 465 |
416 // Capture the exception. | 466 // Capture the exception. |
417 unsigned int exit_code = client->delegate()->ExceptionHandlerServerException( | 467 unsigned int exit_code = client->delegate()->ExceptionHandlerServerException( |
418 client->process(), client->exception_information_address()); | 468 client->process(), client->crash_exception_information_address()); |
419 | 469 |
420 TerminateProcess(client->process(), exit_code); | 470 TerminateProcess(client->process(), exit_code); |
421 } | 471 } |
422 | 472 |
423 // static | 473 // static |
| 474 void __stdcall ExceptionHandlerServer::OnNonCrashDumpEvent(void* ctx, BOOLEAN) { |
| 475 // This function is executed on the thread pool. |
| 476 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
| 477 base::AutoLock lock(*client->lock()); |
| 478 |
| 479 // Capture the exception. |
| 480 client->delegate()->ExceptionHandlerServerException( |
| 481 client->process(), client->non_crash_exception_information_address()); |
| 482 |
| 483 bool result = SetEvent(client->non_crash_dump_completed_event()); |
| 484 PLOG_IF(ERROR, !result) << "SetEvent"; |
| 485 } |
| 486 |
| 487 // static |
424 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { | 488 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { |
425 // This function is executed on the thread pool. | 489 // This function is executed on the thread pool. |
426 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 490 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
427 base::AutoLock lock(*client->lock()); | 491 base::AutoLock lock(*client->lock()); |
428 | 492 |
429 // Post back to the main thread to have it delete this client record. | 493 // Post back to the main thread to have it delete this client record. |
430 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); | 494 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); |
431 } | 495 } |
432 | 496 |
433 } // namespace crashpad | 497 } // namespace crashpad |
OLD | NEW |