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 |