| 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, |
| 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 #include <signal.h> |
| 18 #include <stdint.h> | 19 #include <stdint.h> |
| 19 #include <string.h> | 20 #include <string.h> |
| 20 | 21 |
| 21 #include <memory> | 22 #include <memory> |
| 22 | 23 |
| 23 #include "base/atomicops.h" | 24 #include "base/atomicops.h" |
| 24 #include "base/logging.h" | 25 #include "base/logging.h" |
| 25 #include "base/macros.h" | 26 #include "base/macros.h" |
| 26 #include "base/scoped_generic.h" | 27 #include "base/scoped_generic.h" |
| 27 #include "base/strings/string16.h" | 28 #include "base/strings/string16.h" |
| 28 #include "base/strings/stringprintf.h" | 29 #include "base/strings/stringprintf.h" |
| 29 #include "base/strings/utf_string_conversions.h" | 30 #include "base/strings/utf_string_conversions.h" |
| 30 #include "base/synchronization/lock.h" | 31 #include "base/synchronization/lock.h" |
| 31 #include "util/file/file_io.h" | 32 #include "util/file/file_io.h" |
| 32 #include "util/misc/random_string.h" | 33 #include "util/misc/random_string.h" |
| 33 #include "util/win/address_types.h" | 34 #include "util/win/address_types.h" |
| 35 #include "util/win/capture_context.h" |
| 34 #include "util/win/command_line.h" | 36 #include "util/win/command_line.h" |
| 35 #include "util/win/critical_section_with_debug_info.h" | 37 #include "util/win/critical_section_with_debug_info.h" |
| 36 #include "util/win/get_function.h" | 38 #include "util/win/get_function.h" |
| 37 #include "util/win/handle.h" | 39 #include "util/win/handle.h" |
| 38 #include "util/win/initial_client_data.h" | 40 #include "util/win/initial_client_data.h" |
| 39 #include "util/win/nt_internals.h" | 41 #include "util/win/nt_internals.h" |
| 40 #include "util/win/ntstatus_logging.h" | 42 #include "util/win/ntstatus_logging.h" |
| 41 #include "util/win/process_info.h" | 43 #include "util/win/process_info.h" |
| 42 #include "util/win/registration_protocol_win.h" | 44 #include "util/win/registration_protocol_win.h" |
| 43 #include "util/win/scoped_process_suspend.h" | 45 #include "util/win/scoped_process_suspend.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 while ( | 103 while ( |
| 102 (startup_state = base::subtle::Release_Load(&g_handler_startup_state)) == | 104 (startup_state = base::subtle::Release_Load(&g_handler_startup_state)) == |
| 103 static_cast<int>(StartupState::kNotReady)) { | 105 static_cast<int>(StartupState::kNotReady)) { |
| 104 Sleep(1); | 106 Sleep(1); |
| 105 } | 107 } |
| 106 | 108 |
| 107 return static_cast<StartupState>(startup_state); | 109 return static_cast<StartupState>(startup_state); |
| 108 } | 110 } |
| 109 | 111 |
| 110 #if defined(ADDRESS_SANITIZER) | 112 #if defined(ADDRESS_SANITIZER) |
| 111 extern "C" LONG | 113 extern "C" LONG __asan_unhandled_exception_filter(EXCEPTION_POINTERS* info); |
| 112 __asan_unhandled_exception_filter(EXCEPTION_POINTERS* info); | |
| 113 #endif | 114 #endif |
| 114 | 115 |
| 115 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 116 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
| 117 #if defined(ADDRESS_SANITIZER) |
| 116 // In ASan builds, delegate to the ASan exception filter. | 118 // In ASan builds, delegate to the ASan exception filter. |
| 117 #if defined(ADDRESS_SANITIZER) | |
| 118 LONG status = __asan_unhandled_exception_filter(exception_pointers); | 119 LONG status = __asan_unhandled_exception_filter(exception_pointers); |
| 119 if (status != EXCEPTION_CONTINUE_SEARCH) | 120 if (status != EXCEPTION_CONTINUE_SEARCH) |
| 120 return status; | 121 return status; |
| 121 #endif | 122 #endif |
| 122 | 123 |
| 123 if (BlockUntilHandlerStartedOrFailed() == StartupState::kFailed) { | 124 if (BlockUntilHandlerStartedOrFailed() == StartupState::kFailed) { |
| 124 // If we know for certain that the handler has failed to start, then abort | 125 // If we know for certain that the handler has failed to start, then abort |
| 125 // here, rather than trying to signal to a handler that will never arrive, | 126 // here, rather than trying to signal to a handler that will never arrive, |
| 126 // and then sleeping unnecessarily. | 127 // and then sleeping unnecessarily. |
| 127 LOG(ERROR) << "crash server failed to launch, self-terminating"; | 128 LOG(ERROR) << "crash server failed to launch, self-terminating"; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 // around. This would ideally never happen. | 169 // around. This would ideally never happen. |
| 169 Sleep(kMillisecondsUntilTerminate); | 170 Sleep(kMillisecondsUntilTerminate); |
| 170 | 171 |
| 171 LOG(ERROR) << "crash server did not respond, self-terminating"; | 172 LOG(ERROR) << "crash server did not respond, self-terminating"; |
| 172 | 173 |
| 173 TerminateProcess(GetCurrentProcess(), kTerminationCodeCrashNoDump); | 174 TerminateProcess(GetCurrentProcess(), kTerminationCodeCrashNoDump); |
| 174 | 175 |
| 175 return EXCEPTION_CONTINUE_SEARCH; | 176 return EXCEPTION_CONTINUE_SEARCH; |
| 176 } | 177 } |
| 177 | 178 |
| 179 void HandleAbortSignal(int signum) { |
| 180 DCHECK_EQ(signum, SIGABRT); |
| 181 |
| 182 CONTEXT context; |
| 183 CaptureContext(&context); |
| 184 |
| 185 EXCEPTION_RECORD record = {}; |
| 186 record.ExceptionCode = STATUS_FATAL_APP_EXIT; |
| 187 record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; |
| 188 #if defined(ARCH_CPU_64_BITS) |
| 189 record.ExceptionAddress = reinterpret_cast<void*>(context.Rip); |
| 190 #else |
| 191 record.ExceptionAddress = reinterpret_cast<void*>(context.Eip); |
| 192 #endif // ARCH_CPU_64_BITS |
| 193 |
| 194 EXCEPTION_POINTERS exception_pointers; |
| 195 exception_pointers.ContextRecord = &context; |
| 196 exception_pointers.ExceptionRecord = &record; |
| 197 |
| 198 UnhandledExceptionHandler(&exception_pointers); |
| 199 } |
| 200 |
| 178 std::wstring FormatArgumentString(const std::string& name, | 201 std::wstring FormatArgumentString(const std::string& name, |
| 179 const std::wstring& value) { | 202 const std::wstring& value) { |
| 180 return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value; | 203 return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value; |
| 181 } | 204 } |
| 182 | 205 |
| 183 struct ScopedProcThreadAttributeListTraits { | 206 struct ScopedProcThreadAttributeListTraits { |
| 184 static PPROC_THREAD_ATTRIBUTE_LIST InvalidValue() { return nullptr; } | 207 static PPROC_THREAD_ATTRIBUTE_LIST InvalidValue() { return nullptr; } |
| 185 | 208 |
| 186 static void Free(PPROC_THREAD_ATTRIBUTE_LIST proc_thread_attribute_list) { | 209 static void Free(PPROC_THREAD_ATTRIBUTE_LIST proc_thread_attribute_list) { |
| 187 // This is able to use GET_FUNCTION_REQUIRED() instead of GET_FUNCTION() | 210 // This is able to use GET_FUNCTION_REQUIRED() instead of GET_FUNCTION() |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 // allows us to walk the list at crash time to gather data for !locks. A | 528 // allows us to walk the list at crash time to gather data for !locks. A |
| 506 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head | 529 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head |
| 507 // of the list. But that is not an exported symbol, so on an arbitrary client | 530 // of the list. But that is not an exported symbol, so on an arbitrary client |
| 508 // machine, we don't have a way of getting that pointer. | 531 // machine, we don't have a way of getting that pointer. |
| 509 InitializeCriticalSectionWithDebugInfoIfPossible( | 532 InitializeCriticalSectionWithDebugInfoIfPossible( |
| 510 &g_critical_section_with_debug_info); | 533 &g_critical_section_with_debug_info); |
| 511 | 534 |
| 512 g_non_crash_dump_lock = new base::Lock(); | 535 g_non_crash_dump_lock = new base::Lock(); |
| 513 } | 536 } |
| 514 | 537 |
| 538 void RegisterHandlers() { |
| 539 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
| 540 |
| 541 // The Windows CRT's signal.h lists: |
| 542 // - SIGINT |
| 543 // - SIGILL |
| 544 // - SIGFPE |
| 545 // - SIGSEGV |
| 546 // - SIGTERM |
| 547 // - SIGBREAK |
| 548 // - SIGABRT |
| 549 // SIGILL and SIGTERM are documented as not being generated. SIGBREAK and |
| 550 // SIGINT are for Ctrl-Break and Ctrl-C, and aren't something for which |
| 551 // capturing a dump is warranted. SIGFPE and SIGSEGV are captured as regular |
| 552 // exceptions through the unhandled exception filter. This leaves SIGABRT. In |
| 553 // the standard CRT, abort() is implemented as a synchronous call to the |
| 554 // SIGABRT signal handler if installed, but after doing so, the unhandled |
| 555 // exception filter is not triggered (it instead __fastfail()s). So, register |
| 556 // to handle SIGABRT to catch abort() calls, as client code might use this and |
| 557 // expect it to cause a crash dump. This will only work when the abort() |
| 558 // that's called in client code is the same (or has the same behavior) as the |
| 559 // one in use here. |
| 560 void (*rv)(int) = signal(SIGABRT, HandleAbortSignal); |
| 561 DCHECK_NE(rv, SIG_ERR); |
| 562 } |
| 563 |
| 515 } // namespace | 564 } // namespace |
| 516 | 565 |
| 517 CrashpadClient::CrashpadClient() : ipc_pipe_(), handler_start_thread_() {} | 566 CrashpadClient::CrashpadClient() : ipc_pipe_(), handler_start_thread_() {} |
| 518 | 567 |
| 519 CrashpadClient::~CrashpadClient() {} | 568 CrashpadClient::~CrashpadClient() {} |
| 520 | 569 |
| 521 bool CrashpadClient::StartHandler( | 570 bool CrashpadClient::StartHandler( |
| 522 const base::FilePath& handler, | 571 const base::FilePath& handler, |
| 523 const base::FilePath& database, | 572 const base::FilePath& database, |
| 524 const base::FilePath& metrics_dir, | 573 const base::FilePath& metrics_dir, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 541 | 590 |
| 542 g_signal_exception = | 591 g_signal_exception = |
| 543 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); | 592 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); |
| 544 g_signal_non_crash_dump = | 593 g_signal_non_crash_dump = |
| 545 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); | 594 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); |
| 546 g_non_crash_dump_done = | 595 g_non_crash_dump_done = |
| 547 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); | 596 CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); |
| 548 | 597 |
| 549 CommonInProcessInitialization(); | 598 CommonInProcessInitialization(); |
| 550 | 599 |
| 551 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 600 RegisterHandlers(); |
| 552 | 601 |
| 553 auto data = new BackgroundHandlerStartThreadData(handler, | 602 auto data = new BackgroundHandlerStartThreadData(handler, |
| 554 database, | 603 database, |
| 555 metrics_dir, | 604 metrics_dir, |
| 556 url, | 605 url, |
| 557 annotations, | 606 annotations, |
| 558 arguments, | 607 arguments, |
| 559 ipc_pipe_, | 608 ipc_pipe_, |
| 560 std::move(ipc_pipe_handle)); | 609 std::move(ipc_pipe_handle)); |
| 561 | 610 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 message.registration.critical_section_address = | 663 message.registration.critical_section_address = |
| 615 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); | 664 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); |
| 616 | 665 |
| 617 ServerToClientMessage response = {}; | 666 ServerToClientMessage response = {}; |
| 618 | 667 |
| 619 if (!SendToCrashHandlerServer(ipc_pipe_, message, &response)) { | 668 if (!SendToCrashHandlerServer(ipc_pipe_, message, &response)) { |
| 620 return false; | 669 return false; |
| 621 } | 670 } |
| 622 | 671 |
| 623 SetHandlerStartupState(StartupState::kSucceeded); | 672 SetHandlerStartupState(StartupState::kSucceeded); |
| 624 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 673 |
| 674 RegisterHandlers(); |
| 625 | 675 |
| 626 // The server returns these already duplicated to be valid in this process. | 676 // The server returns these already duplicated to be valid in this process. |
| 627 g_signal_exception = | 677 g_signal_exception = |
| 628 IntToHandle(response.registration.request_crash_dump_event); | 678 IntToHandle(response.registration.request_crash_dump_event); |
| 629 g_signal_non_crash_dump = | 679 g_signal_non_crash_dump = |
| 630 IntToHandle(response.registration.request_non_crash_dump_event); | 680 IntToHandle(response.registration.request_non_crash_dump_event); |
| 631 g_non_crash_dump_done = | 681 g_non_crash_dump_done = |
| 632 IntToHandle(response.registration.non_crash_dump_completed_event); | 682 IntToHandle(response.registration.non_crash_dump_completed_event); |
| 633 | 683 |
| 634 return true; | 684 return true; |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 status = NtClose(injected_thread); | 1019 status = NtClose(injected_thread); |
| 970 if (!NT_SUCCESS(status)) { | 1020 if (!NT_SUCCESS(status)) { |
| 971 NTSTATUS_LOG(ERROR, status) << "NtClose"; | 1021 NTSTATUS_LOG(ERROR, status) << "NtClose"; |
| 972 result = false; | 1022 result = false; |
| 973 } | 1023 } |
| 974 | 1024 |
| 975 return result; | 1025 return result; |
| 976 } | 1026 } |
| 977 | 1027 |
| 978 } // namespace crashpad | 1028 } // namespace crashpad |
| OLD | NEW |