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 |
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); |
| 140 DCHECK(!g_critical_section_with_debug_info.DebugInfo); |
121 | 141 |
122 ClientToServerMessage message; | 142 ClientToServerMessage message; |
123 memset(&message, 0, sizeof(message)); | 143 memset(&message, 0, sizeof(message)); |
124 message.type = ClientToServerMessage::kRegister; | 144 message.type = ClientToServerMessage::kRegister; |
125 message.registration.version = RegistrationRequest::kMessageVersion; | 145 message.registration.version = RegistrationRequest::kMessageVersion; |
126 message.registration.client_process_id = GetCurrentProcessId(); | 146 message.registration.client_process_id = GetCurrentProcessId(); |
127 message.registration.crash_exception_information = | 147 message.registration.crash_exception_information = |
128 reinterpret_cast<WinVMAddress>(&g_crash_exception_information); | 148 reinterpret_cast<WinVMAddress>(&g_crash_exception_information); |
129 message.registration.non_crash_exception_information = | 149 message.registration.non_crash_exception_information = |
130 reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information); | 150 reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information); |
131 | 151 |
| 152 // We create this dummy CRITICAL_SECTION with the |
| 153 // RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO flag set to have an entry point |
| 154 // into the doubly-linked list of RTL_CRITICAL_SECTION_DEBUG objects. This |
| 155 // allows us to walk the list at crash time to gather data for !locks. A |
| 156 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head |
| 157 // of the list. But that is not an exported symbol, so on an arbitrary client |
| 158 // machine, we don't have a way of getting that pointer. |
| 159 if (CrashpadInitializeCriticalSectionEx( |
| 160 &g_critical_section_with_debug_info, |
| 161 0, |
| 162 RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO)) { |
| 163 message.registration.critical_section_address = |
| 164 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); |
| 165 } else { |
| 166 PLOG(ERROR) << "InitializeCriticalSectionEx"; |
| 167 } |
| 168 |
132 ServerToClientMessage response = {0}; | 169 ServerToClientMessage response = {0}; |
133 | 170 |
134 if (!SendToCrashHandlerServer( | 171 if (!SendToCrashHandlerServer( |
135 base::UTF8ToUTF16(ipc_port), message, &response)) { | 172 base::UTF8ToUTF16(ipc_port), message, &response)) { |
136 return false; | 173 return false; |
137 } | 174 } |
138 | 175 |
139 // The server returns these already duplicated to be valid in this process. | 176 // The server returns these already duplicated to be valid in this process. |
140 g_signal_exception = reinterpret_cast<HANDLE>( | 177 g_signal_exception = reinterpret_cast<HANDLE>( |
141 static_cast<uintptr_t>(response.registration.request_crash_dump_event)); | 178 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); | 245 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
209 | 246 |
210 bool set_event_result = SetEvent(g_signal_non_crash_dump); | 247 bool set_event_result = SetEvent(g_signal_non_crash_dump); |
211 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; | 248 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
212 | 249 |
213 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); | 250 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
214 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; | 251 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
215 } | 252 } |
216 | 253 |
217 } // namespace crashpad | 254 } // namespace crashpad |
OLD | NEW |