| 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 |