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 |
| 52 // RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO to force it to be allocated with a |
| 53 // valid .DebugInfo field. The address of this critical section is given to the |
| 54 // handler. All critical sections with debug info are linked in a doubly-linked |
| 55 // 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 |
(...skipping 15 matching lines...) Expand all Loading... |
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( |
| 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 } else { |
| 165 PLOG(ERROR) << "InitializeCriticalSectionEx"; |
| 166 } |
| 167 |
132 ServerToClientMessage response = {0}; | 168 ServerToClientMessage response = {0}; |
133 | 169 |
134 if (!SendToCrashHandlerServer( | 170 if (!SendToCrashHandlerServer( |
135 base::UTF8ToUTF16(ipc_port), message, &response)) { | 171 base::UTF8ToUTF16(ipc_port), message, &response)) { |
136 return false; | 172 return false; |
137 } | 173 } |
138 | 174 |
139 // The server returns these already duplicated to be valid in this process. | 175 // The server returns these already duplicated to be valid in this process. |
140 g_signal_exception = reinterpret_cast<HANDLE>( | 176 g_signal_exception = reinterpret_cast<HANDLE>( |
141 static_cast<uintptr_t>(response.registration.request_crash_dump_event)); | 177 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); | 244 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
209 | 245 |
210 bool set_event_result = SetEvent(g_signal_non_crash_dump); | 246 bool set_event_result = SetEvent(g_signal_non_crash_dump); |
211 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; | 247 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
212 | 248 |
213 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); | 249 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
214 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; | 250 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
215 } | 251 } |
216 | 252 |
217 } // namespace crashpad | 253 } // namespace crashpad |
OLD | NEW |