Index: client/crashpad_client_win.cc |
diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc |
index e19aa7469d81a8015f5bd9bc70a52f97761ab999..e65206b8d1e0f6a7142cfeaf329e81b6da3a6067 100644 |
--- a/client/crashpad_client_win.cc |
+++ b/client/crashpad_client_win.cc |
@@ -21,17 +21,32 @@ |
#include "base/logging.h" |
#include "base/strings/string16.h" |
#include "base/strings/utf_string_conversions.h" |
+#include "base/synchronization/lock.h" |
#include "util/file/file_io.h" |
#include "util/win/registration_protocol_win.h" |
#include "util/win/scoped_handle.h" |
namespace { |
-// This handle is never closed. |
+// This handle is never closed. This is used to signal to the server that a dump |
+// should be taken in the event of a crash. |
HANDLE g_signal_exception = INVALID_HANDLE_VALUE; |
// Where we store the exception information that the crash handler reads. |
-crashpad::ExceptionInformation g_exception_information; |
+crashpad::ExceptionInformation g_crash_exception_information; |
+ |
+// These handles are never closed. g_signal_non_crash_dump is used to signal to |
+// the server to take a dump (not due to an exception), and the server will |
+// signal g_non_crash_dump_done when the dump is completed. |
+HANDLE g_signal_non_crash_dump = INVALID_HANDLE_VALUE; |
+HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; |
+ |
+// Guards multiple simultaneous calls to DumpWithoutCrash(). |
+base::Lock g_non_crash_dump_lock; |
Mark Mentovai
2015/09/24 20:37:29
This carries a static constructor. This should be
scottmg
2015/09/24 21:16:59
Done.
|
+ |
+// Where we store a pointer to the context information when taking a non-crash |
+// dump. |
+crashpad::ExceptionInformation g_non_crash_exception_information; |
LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
// Tracks whether a thread has already entered UnhandledExceptionHandler. |
@@ -55,8 +70,8 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
// Otherwise, we're the first thread, so record the exception pointer and |
// signal the crash handler. |
- g_exception_information.thread_id = GetCurrentThreadId(); |
- g_exception_information.exception_pointers = |
+ g_crash_exception_information.thread_id = GetCurrentThreadId(); |
+ g_crash_exception_information.exception_pointers = |
reinterpret_cast<crashpad::WinVMAddress>(exception_pointers); |
// Now signal the crash server, which will take a dump and then terminate us |
@@ -107,8 +122,10 @@ bool CrashpadClient::SetHandler(const std::string& ipc_port) { |
message.type = ClientToServerMessage::kRegister; |
message.registration.version = RegistrationRequest::kMessageVersion; |
message.registration.client_process_id = GetCurrentProcessId(); |
- message.registration.exception_information = |
- reinterpret_cast<WinVMAddress>(&g_exception_information); |
+ message.registration.crash_exception_information = |
+ reinterpret_cast<WinVMAddress>(&g_crash_exception_information); |
+ message.registration.non_crash_exception_information = |
+ reinterpret_cast<WinVMAddress>(&g_non_crash_exception_information); |
ServerToClientMessage response = {0}; |
@@ -119,17 +136,63 @@ bool CrashpadClient::SetHandler(const std::string& ipc_port) { |
// The server returns these already duplicated to be valid in this process. |
g_signal_exception = reinterpret_cast<HANDLE>( |
- static_cast<uintptr_t>(response.registration.request_report_event)); |
+ static_cast<uintptr_t>(response.registration.request_crash_dump_event)); |
+ g_signal_non_crash_dump = reinterpret_cast<HANDLE>(static_cast<uintptr_t>( |
+ response.registration.request_non_crash_dump_event)); |
+ g_non_crash_dump_done = reinterpret_cast<HANDLE>(static_cast<uintptr_t>( |
+ response.registration.non_crash_dump_completed_event)); |
+ |
return true; |
} |
bool CrashpadClient::UseHandler() { |
- if (g_signal_exception == INVALID_HANDLE_VALUE) |
+ if (g_signal_exception == INVALID_HANDLE_VALUE || |
+ g_signal_non_crash_dump == INVALID_HANDLE_VALUE || |
+ g_non_crash_dump_done == INVALID_HANDLE_VALUE) { |
return false; |
+ } |
+ |
// In theory we could store the previous handler but it is not clear what |
// use we have for it. |
SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
return true; |
} |
+// static |
+bool CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { |
+ if (g_signal_non_crash_dump == INVALID_HANDLE_VALUE || |
+ g_non_crash_dump_done == INVALID_HANDLE_VALUE) { |
+ LOG(ERROR) << "haven't called SetHandler()"; |
+ return false; |
+ } |
+ |
+ // In the non-crashing case, we aren't concerned about avoiding calls into |
+ // Win32 APIs, so just use regular locking here in case of multiple threads |
+ // calling this function. If a crash occurs while we're in here, the worst |
+ // that can happen is that the server captures a partial dump for this path |
+ // because on the other thread gathering a crash dump, it TerminateProcess()d, |
+ // causing this one to abort. |
+ base::AutoLock lock(g_non_crash_dump_lock); |
+ |
+ // Create a fake EXCEPTION_POINTERS (with a null EXCEPTION_RECORD), so that |
+ // the handler has a CONTEXT to start from. We don't include an |
+ // EXCEPTION_RECORD as there hasn't actually been an exception. |
+ EXCEPTION_POINTERS exception_pointers = {0}; |
+ // This is logically const, but EXCEPTION_POINTERS does not declare it as |
Mark Mentovai
2015/09/24 20:37:29
Blank line before this, so that EXCEPTION_POINTERS
scottmg
2015/09/24 21:16:59
Done.
|
+ // const, so we have to cast that away from the argument. |
+ exception_pointers.ContextRecord = const_cast<CONTEXT*>(&context); |
+ |
+ g_non_crash_exception_information.thread_id = GetCurrentThreadId(); |
+ g_non_crash_exception_information.exception_pointers = |
+ reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
+ |
+ bool set_event_result = SetEvent(g_signal_non_crash_dump); |
+ PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
+ |
+ DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
+ PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
+ |
+ return true; |
+} |
+ |
} // namespace crashpad |