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 |