Chromium Code Reviews| 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 30 matching lines...) Expand all Loading... | |
| 41 HANDLE g_signal_non_crash_dump = INVALID_HANDLE_VALUE; | 41 HANDLE g_signal_non_crash_dump = INVALID_HANDLE_VALUE; |
| 42 HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; | 42 HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; |
| 43 | 43 |
| 44 // Guards multiple simultaneous calls to DumpWithoutCrash(). This is leaked. | 44 // Guards multiple simultaneous calls to DumpWithoutCrash(). This is leaked. |
| 45 base::Lock* g_non_crash_dump_lock; | 45 base::Lock* g_non_crash_dump_lock; |
| 46 | 46 |
| 47 // Where we store a pointer to the context information when taking a non-crash | 47 // Where we store a pointer to the context information when taking a non-crash |
| 48 // dump. | 48 // dump. |
| 49 crashpad::ExceptionInformation g_non_crash_exception_information; | 49 crashpad::ExceptionInformation g_non_crash_exception_information; |
| 50 | 50 |
| 51 // A `CRITICAL_SECTION` initialized with | |
|
Mark Mentovai
2015/10/15 00:14:56
// (as opposed to //!) comments aren’t Doxygenated
scottmg
2015/10/15 18:22:23
Done.
| |
| 52 // `RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO` to force it to be allocated with | |
| 53 // a valid .DebugInfo field. The address of this critical section is given to | |
| 54 // the handler. All critical sections with debug info are linked in a | |
| 55 // doubly-linked list, so this allows the handler to capture all of them. | |
| 56 CRITICAL_SECTION g_critical_section_with_debug_info; | |
| 57 | |
| 51 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 58 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
| 52 // Tracks whether a thread has already entered UnhandledExceptionHandler. | 59 // Tracks whether a thread has already entered UnhandledExceptionHandler. |
| 53 static base::subtle::AtomicWord have_crashed; | 60 static base::subtle::AtomicWord have_crashed; |
| 54 | 61 |
| 55 // This is a per-process handler. While this handler is being invoked, other | 62 // This is a per-process handler. While this handler is being invoked, other |
| 56 // threads are still executing as usual, so multiple threads could enter at | 63 // threads are still executing as usual, so multiple threads could enter at |
| 57 // the same time. Because we're in a crashing state, we shouldn't be doing | 64 // the same time. Because we're in a crashing state, we shouldn't be doing |
| 58 // anything that might cause allocations, call into kernel mode, etc. So, we | 65 // anything that might cause allocations, call into kernel mode, etc. So, we |
| 59 // don't want to take a critical section here to avoid simultaneous access to | 66 // don't want to take a critical section here to avoid simultaneous access to |
| 60 // the global exception pointers in ExceptionInformation. Because the crash | 67 // the global exception pointers in ExceptionInformation. Because the crash |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 87 Sleep(kMillisecondsUntilTerminate); | 94 Sleep(kMillisecondsUntilTerminate); |
| 88 | 95 |
| 89 LOG(ERROR) << "crash server did not respond, self-terminating"; | 96 LOG(ERROR) << "crash server did not respond, self-terminating"; |
| 90 | 97 |
| 91 const UINT kCrashExitCodeNoDump = 0xffff7001; | 98 const UINT kCrashExitCodeNoDump = 0xffff7001; |
| 92 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump); | 99 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump); |
| 93 | 100 |
| 94 return EXCEPTION_CONTINUE_SEARCH; | 101 return EXCEPTION_CONTINUE_SEARCH; |
| 95 } | 102 } |
| 96 | 103 |
| 104 BOOL CrashpadInitializeCriticalSectionEx( | |
| 105 CRITICAL_SECTION* critical_section, | |
| 106 DWORD spin_count, | |
| 107 DWORD flags) { | |
| 108 static decltype(InitializeCriticalSectionEx)* initialize_critical_section_ex = | |
| 109 reinterpret_cast<decltype(InitializeCriticalSectionEx)*>(GetProcAddress( | |
| 110 LoadLibrary(L"kernel32.dll"), "InitializeCriticalSectionEx")); | |
| 111 if (!initialize_critical_section_ex) | |
| 112 return false; | |
| 113 return initialize_critical_section_ex(critical_section, spin_count, flags); | |
| 114 } | |
| 115 | |
| 97 } // namespace | 116 } // namespace |
| 98 | 117 |
| 99 namespace crashpad { | 118 namespace crashpad { |
| 100 | 119 |
| 101 CrashpadClient::CrashpadClient() { | 120 CrashpadClient::CrashpadClient() { |
| 102 } | 121 } |
| 103 | 122 |
| 104 CrashpadClient::~CrashpadClient() { | 123 CrashpadClient::~CrashpadClient() { |
| 105 } | 124 } |
| 106 | 125 |
| 107 bool CrashpadClient::StartHandler( | 126 bool CrashpadClient::StartHandler( |
| 108 const base::FilePath& handler, | 127 const base::FilePath& handler, |
| 109 const base::FilePath& database, | 128 const base::FilePath& database, |
| 110 const std::string& url, | 129 const std::string& url, |
| 111 const std::map<std::string, std::string>& annotations, | 130 const std::map<std::string, std::string>& annotations, |
| 112 const std::vector<std::string>& arguments) { | 131 const std::vector<std::string>& arguments) { |
| 113 LOG(FATAL) << "SetHandler should be used on Windows"; | 132 LOG(FATAL) << "SetHandler should be used on Windows"; |
| 114 return false; | 133 return false; |
| 115 } | 134 } |
| 116 | 135 |
| 117 bool CrashpadClient::SetHandler(const std::string& ipc_port) { | 136 bool CrashpadClient::SetHandler(const std::string& ipc_port) { |
| 118 DCHECK_EQ(g_signal_exception, INVALID_HANDLE_VALUE); | 137 DCHECK_EQ(g_signal_exception, INVALID_HANDLE_VALUE); |
| 119 DCHECK_EQ(g_signal_non_crash_dump, INVALID_HANDLE_VALUE); | 138 DCHECK_EQ(g_signal_non_crash_dump, INVALID_HANDLE_VALUE); |
| 120 DCHECK_EQ(g_non_crash_dump_done, INVALID_HANDLE_VALUE); | 139 DCHECK_EQ(g_non_crash_dump_done, INVALID_HANDLE_VALUE); |
|
Mark Mentovai
2015/10/15 00:14:56
DCHECK that g_critical_section_with_debug_info is
scottmg
2015/10/15 18:22:23
It's not a handle, it's just a POD struct with no
Mark Mentovai
2015/10/15 19:37:58
scottmg wrote:
scottmg
2015/10/15 20:06:41
Done.
| |
| 121 | 140 |
| 122 ClientToServerMessage message; | 141 ClientToServerMessage message; |
| 123 memset(&message, 0, sizeof(message)); | 142 memset(&message, 0, sizeof(message)); |
| 124 message.type = ClientToServerMessage::kRegister; | 143 message.type = ClientToServerMessage::kRegister; |
| 125 message.registration.version = RegistrationRequest::kMessageVersion; | 144 message.registration.version = RegistrationRequest::kMessageVersion; |
| 126 message.registration.client_process_id = GetCurrentProcessId(); | 145 message.registration.client_process_id = GetCurrentProcessId(); |
| 127 message.registration.crash_exception_information = | 146 message.registration.crash_exception_information = |
| 128 reinterpret_cast<WinVMAddress>(&g_crash_exception_information); | 147 reinterpret_cast<WinVMAddress>(&g_crash_exception_information); |
| 129 message.registration.non_crash_exception_information = | 148 message.registration.non_crash_exception_information = |
| 130 reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information); | 149 reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information); |
| 131 | 150 |
| 151 // We create this dummy CRITICAL_SECTION with the | |
| 152 // RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO flag set to have an entry point | |
| 153 // into the doubly-linked list of RTL_CRITICAL_SECTION_DEBUG objects. This | |
| 154 // allows us to walk the list at crash time to gather data for !locks. A | |
| 155 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head | |
| 156 // of the list. But that is not an exported symbol, so on an arbitrary client | |
| 157 // machine, we don't have a way of getting that pointer. | |
| 158 if (CrashpadInitializeCriticalSectionEx( | |
|
Mark Mentovai
2015/10/15 00:14:56
Otherwise, PLOG().
scottmg
2015/10/15 18:22:23
Done.
| |
| 159 &g_critical_section_with_debug_info, | |
| 160 0, | |
| 161 RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO)) { | |
| 162 message.registration.critical_section_address = | |
| 163 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); | |
| 164 } | |
| 165 | |
| 132 ServerToClientMessage response = {0}; | 166 ServerToClientMessage response = {0}; |
| 133 | 167 |
| 134 if (!SendToCrashHandlerServer( | 168 if (!SendToCrashHandlerServer( |
| 135 base::UTF8ToUTF16(ipc_port), message, &response)) { | 169 base::UTF8ToUTF16(ipc_port), message, &response)) { |
| 136 return false; | 170 return false; |
| 137 } | 171 } |
| 138 | 172 |
| 139 // The server returns these already duplicated to be valid in this process. | 173 // The server returns these already duplicated to be valid in this process. |
| 140 g_signal_exception = reinterpret_cast<HANDLE>( | 174 g_signal_exception = reinterpret_cast<HANDLE>( |
| 141 static_cast<uintptr_t>(response.registration.request_crash_dump_event)); | 175 static_cast<uintptr_t>(response.registration.request_crash_dump_event)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); | 242 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
| 209 | 243 |
| 210 bool set_event_result = SetEvent(g_signal_non_crash_dump); | 244 bool set_event_result = SetEvent(g_signal_non_crash_dump); |
| 211 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; | 245 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
| 212 | 246 |
| 213 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); | 247 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
| 214 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; | 248 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
| 215 } | 249 } |
| 216 | 250 |
| 217 } // namespace crashpad | 251 } // namespace crashpad |
| OLD | NEW |