aboutsummaryrefslogtreecommitdiff
path: root/src/client/windows/crash_generation
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/windows/crash_generation')
-rw-r--r--src/client/windows/crash_generation/ReadMe.txt116
-rw-r--r--src/client/windows/crash_generation/client_info.cc294
-rw-r--r--src/client/windows/crash_generation/client_info.h290
-rw-r--r--src/client/windows/crash_generation/crash_generation.vcproj686
-rw-r--r--src/client/windows/crash_generation/crash_generation_client.cc658
-rw-r--r--src/client/windows/crash_generation/crash_generation_client.h302
-rw-r--r--src/client/windows/crash_generation/crash_generation_server.cc1646
-rw-r--r--src/client/windows/crash_generation/crash_generation_server.h520
-rw-r--r--src/client/windows/crash_generation/minidump_generator.cc456
-rw-r--r--src/client/windows/crash_generation/minidump_generator.h236
10 files changed, 2602 insertions, 2602 deletions
diff --git a/src/client/windows/crash_generation/ReadMe.txt b/src/client/windows/crash_generation/ReadMe.txt
index d9ded287..b54d0e11 100644
--- a/src/client/windows/crash_generation/ReadMe.txt
+++ b/src/client/windows/crash_generation/ReadMe.txt
@@ -1,58 +1,58 @@
-=========================================================================
- State machine transitions for the Crash Generation Server
-=========================================================================
-
-=========================================================================
- |
- STATE | ACTIONS
- |
-=========================================================================
- ERROR | Clean up resources used to serve clients.
- | Always remain in ERROR state.
--------------------------------------------------------------------------
- INITIAL | Connect to the pipe asynchronously.
- | If connection is successfully queued up asynchronously,
- | go into CONNECTING state.
- | If connection is done synchronously, go into CONNECTED
- | state.
- | For any unexpected problems, go into ERROR state.
--------------------------------------------------------------------------
- CONNECTING | Get the result of async connection request.
- | If I/O is still incomplete, remain in the CONNECTING
- | state.
- | If connection is complete, go into CONNECTED state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- CONNECTED | Read from the pipe asynchronously.
- | If read request is successfully queued up asynchronously,
- | go into READING state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- READING | Get the result of async read request.
- | If read is done, go into READ_DONE state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- READ_DONE | Register the client, prepare the reply and write the
- | reply to the pipe asynchronously.
- | If write request is successfully queued up asynchronously,
- | go into WRITING state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- WRITING | Get the result of the async write request.
- | If write is done, go into WRITE_DONE state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- WRITE_DONE | Read from the pipe asynchronously (for an ACK).
- | If read request is successfully queued up asynchonously,
- | go into READING_ACK state.
- | For any unexpected problems, go into DISCONNECTING state.
--------------------------------------------------------------------------
- READING_ACK | Get the result of the async read request.
- | If read is done, perform action for successful client
- | connection.
- | Go into DISCONNECTING state.
--------------------------------------------------------------------------
- DISCONNECTING | Disconnect from the pipe, reset the event and go into
- | INITIAL state and signal the event again. If anything
- | fails, go into ERROR state.
-=========================================================================
+=========================================================================
+ State machine transitions for the Crash Generation Server
+=========================================================================
+
+=========================================================================
+ |
+ STATE | ACTIONS
+ |
+=========================================================================
+ ERROR | Clean up resources used to serve clients.
+ | Always remain in ERROR state.
+-------------------------------------------------------------------------
+ INITIAL | Connect to the pipe asynchronously.
+ | If connection is successfully queued up asynchronously,
+ | go into CONNECTING state.
+ | If connection is done synchronously, go into CONNECTED
+ | state.
+ | For any unexpected problems, go into ERROR state.
+-------------------------------------------------------------------------
+ CONNECTING | Get the result of async connection request.
+ | If I/O is still incomplete, remain in the CONNECTING
+ | state.
+ | If connection is complete, go into CONNECTED state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ CONNECTED | Read from the pipe asynchronously.
+ | If read request is successfully queued up asynchronously,
+ | go into READING state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READING | Get the result of async read request.
+ | If read is done, go into READ_DONE state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READ_DONE | Register the client, prepare the reply and write the
+ | reply to the pipe asynchronously.
+ | If write request is successfully queued up asynchronously,
+ | go into WRITING state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ WRITING | Get the result of the async write request.
+ | If write is done, go into WRITE_DONE state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ WRITE_DONE | Read from the pipe asynchronously (for an ACK).
+ | If read request is successfully queued up asynchonously,
+ | go into READING_ACK state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READING_ACK | Get the result of the async read request.
+ | If read is done, perform action for successful client
+ | connection.
+ | Go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ DISCONNECTING | Disconnect from the pipe, reset the event and go into
+ | INITIAL state and signal the event again. If anything
+ | fails, go into ERROR state.
+=========================================================================
diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc
index efd3b029..35dd27b0 100644
--- a/src/client/windows/crash_generation/client_info.cc
+++ b/src/client/windows/crash_generation/client_info.cc
@@ -1,147 +1,147 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "client/windows/crash_generation/client_info.h"
-
-namespace google_breakpad {
-
-ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
- DWORD pid,
- MINIDUMP_TYPE dump_type,
- DWORD* thread_id,
- EXCEPTION_POINTERS** ex_info,
- MDRawAssertionInfo* assert_info)
- : crash_server_(crash_server),
- pid_(pid),
- dump_type_(dump_type),
- ex_info_(ex_info),
- assert_info_(assert_info),
- thread_id_(thread_id),
- process_handle_(NULL),
- dump_requested_handle_(NULL),
- dump_generated_handle_(NULL),
- dump_request_wait_handle_(NULL),
- process_exit_wait_handle_(NULL) {
-}
-
-bool ClientInfo::Initialize() {
- process_handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_);
- if (!process_handle_) {
- return false;
- }
-
- dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
- TRUE, // Manual reset.
- FALSE, // Initial state.
- NULL); // Name.
- if (!dump_requested_handle_) {
- return false;
- }
-
- dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
- TRUE, // Manual reset.
- FALSE, // Initial state.
- NULL); // Name.
- return dump_generated_handle_ != NULL;
-}
-
-ClientInfo::~ClientInfo() {
- if (process_handle_) {
- CloseHandle(process_handle_);
- }
-
- if (dump_requested_handle_) {
- CloseHandle(dump_requested_handle_);
- }
-
- if (dump_generated_handle_) {
- CloseHandle(dump_generated_handle_);
- }
-
- if (dump_request_wait_handle_) {
- // Wait for callbacks that might already be running to finish.
- UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
- }
-
- if (process_exit_wait_handle_) {
- // Wait for the callback that might already be running to finish.
- UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
- }
-}
-
-bool ClientInfo::UnregisterWaits() {
- bool success = true;
-
- if (dump_request_wait_handle_) {
- if (!UnregisterWait(dump_request_wait_handle_)) {
- success = false;
- } else {
- dump_request_wait_handle_ = NULL;
- }
- }
-
- if (process_exit_wait_handle_) {
- if (!UnregisterWait(process_exit_wait_handle_)) {
- success = false;
- } else {
- process_exit_wait_handle_ = NULL;
- }
- }
-
- return success;
-}
-
-bool ClientInfo::GetClientExceptionInfo(
- EXCEPTION_POINTERS** ex_info) const {
- SIZE_T bytes_count = 0;
- if (!ReadProcessMemory(process_handle_,
- ex_info_,
- ex_info,
- sizeof(*ex_info),
- &bytes_count)) {
- return false;
- }
-
- return bytes_count == sizeof(*ex_info);
-}
-
-bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
- SIZE_T bytes_count = 0;
- if (!ReadProcessMemory(process_handle_,
- thread_id_,
- thread_id,
- sizeof(*thread_id),
- &bytes_count)) {
- return false;
- }
-
- return bytes_count == sizeof(*thread_id);
-}
-
-} // namespace google_breakpad
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/client_info.h"
+
+namespace google_breakpad {
+
+ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
+ DWORD pid,
+ MINIDUMP_TYPE dump_type,
+ DWORD* thread_id,
+ EXCEPTION_POINTERS** ex_info,
+ MDRawAssertionInfo* assert_info)
+ : crash_server_(crash_server),
+ pid_(pid),
+ dump_type_(dump_type),
+ ex_info_(ex_info),
+ assert_info_(assert_info),
+ thread_id_(thread_id),
+ process_handle_(NULL),
+ dump_requested_handle_(NULL),
+ dump_generated_handle_(NULL),
+ dump_request_wait_handle_(NULL),
+ process_exit_wait_handle_(NULL) {
+}
+
+bool ClientInfo::Initialize() {
+ process_handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_);
+ if (!process_handle_) {
+ return false;
+ }
+
+ dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
+ TRUE, // Manual reset.
+ FALSE, // Initial state.
+ NULL); // Name.
+ if (!dump_requested_handle_) {
+ return false;
+ }
+
+ dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
+ TRUE, // Manual reset.
+ FALSE, // Initial state.
+ NULL); // Name.
+ return dump_generated_handle_ != NULL;
+}
+
+ClientInfo::~ClientInfo() {
+ if (process_handle_) {
+ CloseHandle(process_handle_);
+ }
+
+ if (dump_requested_handle_) {
+ CloseHandle(dump_requested_handle_);
+ }
+
+ if (dump_generated_handle_) {
+ CloseHandle(dump_generated_handle_);
+ }
+
+ if (dump_request_wait_handle_) {
+ // Wait for callbacks that might already be running to finish.
+ UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
+ }
+
+ if (process_exit_wait_handle_) {
+ // Wait for the callback that might already be running to finish.
+ UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
+ }
+}
+
+bool ClientInfo::UnregisterWaits() {
+ bool success = true;
+
+ if (dump_request_wait_handle_) {
+ if (!UnregisterWait(dump_request_wait_handle_)) {
+ success = false;
+ } else {
+ dump_request_wait_handle_ = NULL;
+ }
+ }
+
+ if (process_exit_wait_handle_) {
+ if (!UnregisterWait(process_exit_wait_handle_)) {
+ success = false;
+ } else {
+ process_exit_wait_handle_ = NULL;
+ }
+ }
+
+ return success;
+}
+
+bool ClientInfo::GetClientExceptionInfo(
+ EXCEPTION_POINTERS** ex_info) const {
+ SIZE_T bytes_count = 0;
+ if (!ReadProcessMemory(process_handle_,
+ ex_info_,
+ ex_info,
+ sizeof(*ex_info),
+ &bytes_count)) {
+ return false;
+ }
+
+ return bytes_count == sizeof(*ex_info);
+}
+
+bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
+ SIZE_T bytes_count = 0;
+ if (!ReadProcessMemory(process_handle_,
+ thread_id_,
+ thread_id,
+ sizeof(*thread_id),
+ &bytes_count)) {
+ return false;
+ }
+
+ return bytes_count == sizeof(*thread_id);
+}
+
+} // namespace google_breakpad
diff --git a/src/client/windows/crash_generation/client_info.h b/src/client/windows/crash_generation/client_info.h
index 06de6311..9956c47a 100644
--- a/src/client/windows/crash_generation/client_info.h
+++ b/src/client/windows/crash_generation/client_info.h
@@ -1,145 +1,145 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
-#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
-
-#include <Windows.h>
-#include <DbgHelp.h>
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-class CrashGenerationServer;
-
-// Abstraction for a crash client process.
-class ClientInfo {
- public:
- // Creates an instance with the given values. Gets the process
- // handle for the given process id and creates necessary event
- // objects.
- ClientInfo(CrashGenerationServer* crash_server,
- DWORD pid,
- MINIDUMP_TYPE dump_type,
- DWORD* thread_id,
- EXCEPTION_POINTERS** ex_info,
- MDRawAssertionInfo* assert_info);
-
- ~ClientInfo();
-
- CrashGenerationServer* crash_server() const { return crash_server_; }
- DWORD pid() const { return pid_; }
- MINIDUMP_TYPE dump_type() const { return dump_type_; }
- EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
- MDRawAssertionInfo* assert_info() const { return assert_info_; }
- DWORD* thread_id() const { return thread_id_; }
- HANDLE process_handle() const { return process_handle_; }
- HANDLE dump_requested_handle() const { return dump_requested_handle_; }
- HANDLE dump_generated_handle() const { return dump_generated_handle_; }
-
- HANDLE dump_request_wait_handle() const {
- return dump_request_wait_handle_;
- }
-
- void set_dump_request_wait_handle(HANDLE value) {
- dump_request_wait_handle_ = value;
- }
-
- HANDLE process_exit_wait_handle() const {
- return process_exit_wait_handle_;
- }
-
- void set_process_exit_wait_handle(HANDLE value) {
- process_exit_wait_handle_ = value;
- }
-
- // Unregister all waits for the client.
- bool UnregisterWaits();
-
- bool Initialize();
- bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
- bool GetClientThreadId(DWORD* thread_id) const;
-
- private:
- // Crash generation server.
- CrashGenerationServer* crash_server_;
-
- // Client process ID.
- DWORD pid_;
-
- // Dump type requested by the client.
- MINIDUMP_TYPE dump_type_;
-
- // Address of an EXCEPTION_POINTERS* variable in the client
- // process address space that will point to an instance of
- // EXCEPTION_POINTERS containing information about crash.
- //
- // WARNING: Do not dereference these pointers as they are pointers
- // in the address space of another process.
- EXCEPTION_POINTERS** ex_info_;
-
- // Address of an instance of MDRawAssertionInfo in the client
- // process address space that will contain information about
- // non-exception related crashes like invalid parameter assertion
- // failures and pure calls.
- //
- // WARNING: Do not dereference these pointers as they are pointers
- // in the address space of another process.
- MDRawAssertionInfo* assert_info_;
-
- // Address of a variable in the client process address space that
- // will contain the thread id of the crashing client thread.
- //
- // WARNING: Do not dereference these pointers as they are pointers
- // in the address space of another process.
- DWORD* thread_id_;
-
- // Client process handle.
- HANDLE process_handle_;
-
- // Dump request event handle.
- HANDLE dump_requested_handle_;
-
- // Dump generated event handle.
- HANDLE dump_generated_handle_;
-
- // Wait handle for dump request event.
- HANDLE dump_request_wait_handle_;
-
- // Wait handle for process exit event.
- HANDLE process_exit_wait_handle_;
-
- // Disallow copy ctor and operator=.
- ClientInfo(const ClientInfo& client_info);
- ClientInfo& operator=(const ClientInfo& client_info);
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+
+#include <Windows.h>
+#include <DbgHelp.h>
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+class CrashGenerationServer;
+
+// Abstraction for a crash client process.
+class ClientInfo {
+ public:
+ // Creates an instance with the given values. Gets the process
+ // handle for the given process id and creates necessary event
+ // objects.
+ ClientInfo(CrashGenerationServer* crash_server,
+ DWORD pid,
+ MINIDUMP_TYPE dump_type,
+ DWORD* thread_id,
+ EXCEPTION_POINTERS** ex_info,
+ MDRawAssertionInfo* assert_info);
+
+ ~ClientInfo();
+
+ CrashGenerationServer* crash_server() const { return crash_server_; }
+ DWORD pid() const { return pid_; }
+ MINIDUMP_TYPE dump_type() const { return dump_type_; }
+ EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
+ MDRawAssertionInfo* assert_info() const { return assert_info_; }
+ DWORD* thread_id() const { return thread_id_; }
+ HANDLE process_handle() const { return process_handle_; }
+ HANDLE dump_requested_handle() const { return dump_requested_handle_; }
+ HANDLE dump_generated_handle() const { return dump_generated_handle_; }
+
+ HANDLE dump_request_wait_handle() const {
+ return dump_request_wait_handle_;
+ }
+
+ void set_dump_request_wait_handle(HANDLE value) {
+ dump_request_wait_handle_ = value;
+ }
+
+ HANDLE process_exit_wait_handle() const {
+ return process_exit_wait_handle_;
+ }
+
+ void set_process_exit_wait_handle(HANDLE value) {
+ process_exit_wait_handle_ = value;
+ }
+
+ // Unregister all waits for the client.
+ bool UnregisterWaits();
+
+ bool Initialize();
+ bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
+ bool GetClientThreadId(DWORD* thread_id) const;
+
+ private:
+ // Crash generation server.
+ CrashGenerationServer* crash_server_;
+
+ // Client process ID.
+ DWORD pid_;
+
+ // Dump type requested by the client.
+ MINIDUMP_TYPE dump_type_;
+
+ // Address of an EXCEPTION_POINTERS* variable in the client
+ // process address space that will point to an instance of
+ // EXCEPTION_POINTERS containing information about crash.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ EXCEPTION_POINTERS** ex_info_;
+
+ // Address of an instance of MDRawAssertionInfo in the client
+ // process address space that will contain information about
+ // non-exception related crashes like invalid parameter assertion
+ // failures and pure calls.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ MDRawAssertionInfo* assert_info_;
+
+ // Address of a variable in the client process address space that
+ // will contain the thread id of the crashing client thread.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ DWORD* thread_id_;
+
+ // Client process handle.
+ HANDLE process_handle_;
+
+ // Dump request event handle.
+ HANDLE dump_requested_handle_;
+
+ // Dump generated event handle.
+ HANDLE dump_generated_handle_;
+
+ // Wait handle for dump request event.
+ HANDLE dump_request_wait_handle_;
+
+ // Wait handle for process exit event.
+ HANDLE process_exit_wait_handle_;
+
+ // Disallow copy ctor and operator=.
+ ClientInfo(const ClientInfo& client_info);
+ ClientInfo& operator=(const ClientInfo& client_info);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
diff --git a/src/client/windows/crash_generation/crash_generation.vcproj b/src/client/windows/crash_generation/crash_generation.vcproj
index 615876e9..055ced6e 100644
--- a/src/client/windows/crash_generation/crash_generation.vcproj
+++ b/src/client/windows/crash_generation/crash_generation.vcproj
@@ -1,343 +1,343 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="8.00"
- Name="crash_generation"
- ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
- RootNamespace="CrashGenerationServer"
- Keyword="Win32Proj"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="4"
- CharacterSet="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\.."
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- WarningLevel="4"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="4"
- CharacterSet="1"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\.."
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
- RuntimeLibrary="2"
- UsePrecompiledHeader="0"
- WarningLevel="4"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="3"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="DebugStaticCRT|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="4"
- CharacterSet="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\.."
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- WarningLevel="4"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="ReleaseStaticCRT|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="4"
- CharacterSet="1"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\.."
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
- RuntimeLibrary="0"
- UsePrecompiledHeader="0"
- WarningLevel="4"
- Detect64BitPortabilityProblems="true"
- DebugInformationFormat="3"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLibrarianTool"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath=".\client_info.cc"
- >
- </File>
- <File
- RelativePath=".\crash_generation_client.cc"
- >
- </File>
- <File
- RelativePath=".\crash_generation_server.cc"
- >
- </File>
- <File
- RelativePath="..\..\..\common\windows\guid_string.cc"
- >
- </File>
- <File
- RelativePath=".\minidump_generator.cc"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="..\common\auto_critical_section.h"
- >
- </File>
- <File
- RelativePath=".\client_info.h"
- >
- </File>
- <File
- RelativePath=".\crash_generation_client.h"
- >
- </File>
- <File
- RelativePath=".\crash_generation_server.h"
- >
- </File>
- <File
- RelativePath="..\common\ipc_protocol.h"
- >
- </File>
- <File
- RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
- >
- </File>
- <File
- RelativePath=".\minidump_generator.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- </Filter>
- <File
- RelativePath=".\ReadMe.txt"
- >
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="crash_generation"
+ ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
+ RootNamespace="CrashGenerationServer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="DebugStaticCRT|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseStaticCRT|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\client_info.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\crash_generation_client.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\crash_generation_server.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\common\windows\guid_string.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\minidump_generator.cc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\common\auto_critical_section.h"
+ >
+ </File>
+ <File
+ RelativePath=".\client_info.h"
+ >
+ </File>
+ <File
+ RelativePath=".\crash_generation_client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\crash_generation_server.h"
+ >
+ </File>
+ <File
+ RelativePath="..\common\ipc_protocol.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
+ >
+ </File>
+ <File
+ RelativePath=".\minidump_generator.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/client/windows/crash_generation/crash_generation_client.cc b/src/client/windows/crash_generation/crash_generation_client.cc
index 77c698b1..4ec932c3 100644
--- a/src/client/windows/crash_generation/crash_generation_client.cc
+++ b/src/client/windows/crash_generation/crash_generation_client.cc
@@ -1,329 +1,329 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "client/windows/crash_generation/crash_generation_client.h"
-#include <cassert>
-#include "client/windows/common/ipc_protocol.h"
-
-namespace google_breakpad {
-
-const int kPipeBusyWaitTimeoutMs = 2000;
-
-#ifdef _DEBUG
-const DWORD kWaitForServerTimeoutMs = INFINITE;
-#else
-const DWORD kWaitForServerTimeoutMs = 15000;
-#endif
-
-const int kPipeConnectMaxAttempts = 2;
-
-const DWORD kPipeDesiredAccess = FILE_READ_DATA |
- FILE_WRITE_DATA |
- FILE_WRITE_ATTRIBUTES;
-
-const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
- SECURITY_SQOS_PRESENT;
-
-const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
-
-const size_t kWaitEventCount = 2;
-
-// This function is orphan for production code. It can be used
-// for debugging to help repro some scenarios like the client
-// is slow in writing to the pipe after connecting, the client
-// is slow in reading from the pipe after writing, etc. The parameter
-// overlapped below is not used and it is present to match the signature
-// of this function to TransactNamedPipe Win32 API. Uncomment if needed
-// for debugging.
-/**
-static bool TransactNamedPipeDebugHelper(HANDLE pipe,
- const void* in_buffer,
- DWORD in_size,
- void* out_buffer,
- DWORD out_size,
- DWORD* bytes_count,
- LPOVERLAPPED) {
- // Uncomment the next sleep to create a gap before writing
- // to pipe.
- // Sleep(5000);
-
- if (!WriteFile(pipe,
- in_buffer,
- in_size,
- bytes_count,
- NULL)) {
- return false;
- }
-
- // Uncomment the next sleep to create a gap between write
- // and read.
- // Sleep(5000);
-
- return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
-}
-**/
-
-CrashGenerationClient::CrashGenerationClient(const wchar_t* pipe_name,
- MINIDUMP_TYPE dump_type)
- : pipe_name_(pipe_name),
- dump_type_(dump_type),
- thread_id_(0),
- server_process_id_(0),
- crash_event_(NULL),
- crash_generated_(NULL),
- server_alive_(NULL),
- exception_pointers_(NULL) {
- memset(&assert_info_, 0, sizeof(assert_info_));
-}
-
-CrashGenerationClient::~CrashGenerationClient() {
- if (crash_event_) {
- CloseHandle(crash_event_);
- }
-
- if (crash_generated_) {
- CloseHandle(crash_generated_);
- }
-
- if (server_alive_) {
- CloseHandle(server_alive_);
- }
-}
-
-// Performs the registration step with the server process.
-// The registration step involves communicating with the server
-// via a named pipe. The client sends the following pieces of
-// data to the server:
-//
-// * Message tag indicating the client is requesting registration.
-// * Process id of the client process.
-// * Address of a DWORD variable in the client address space
-// that will contain the thread id of the client thread that
-// caused the crash.
-// * Address of a EXCEPTION_POINTERS* variable in the client
-// address space that will point to an instance of EXCEPTION_POINTERS
-// when the crash happens.
-// * Address of an instance of MDRawAssertionInfo that will contain
-// relevant information in case of non-exception crashes like assertion
-// failures and pure calls.
-//
-// In return the client expects the following information from the server:
-//
-// * Message tag indicating successful registration.
-// * Server process id.
-// * Handle to an object that client can signal to request dump
-// generation from the server.
-// * Handle to an object that client can wait on after requesting
-// dump generation for the server to finish dump generation.
-// * Handle to a mutex object that client can wait on to make sure
-// server is still alive.
-//
-// If any step of the expected behavior mentioned above fails, the
-// registration step is not considered successful and hence out-of-process
-// dump generation service is not available.
-//
-// Returns true if the registration is successful; false otherwise.
-bool CrashGenerationClient::Register() {
- HANDLE pipe = ConnectToServer();
- if (!pipe) {
- return false;
- }
-
- bool success = RegisterClient(pipe);
- CloseHandle(pipe);
- return success;
-}
-
-HANDLE CrashGenerationClient::ConnectToServer() {
- HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
- kPipeDesiredAccess,
- kPipeFlagsAndAttributes);
- if (!pipe) {
- return NULL;
- }
-
- DWORD mode = kPipeMode;
- if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
- CloseHandle(pipe);
- pipe = NULL;
- }
-
- return pipe;
-}
-
-bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
- ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
- GetCurrentProcessId(),
- dump_type_,
- &thread_id_,
- &exception_pointers_,
- &assert_info_,
- NULL,
- NULL,
- NULL);
- ProtocolMessage reply;
- DWORD bytes_count = 0;
- // The call to TransactNamedPipe below can be changed to a call
- // to TransactNamedPipeDebugHelper to help repro some scenarios.
- // For details see comments for TransactNamedPipeDebugHelper.
- if (!TransactNamedPipe(pipe,
- &msg,
- sizeof(msg),
- &reply,
- sizeof(ProtocolMessage),
- &bytes_count,
- NULL)) {
- return false;
- }
-
- if (!ValidateResponse(reply)) {
- return false;
- }
-
- ProtocolMessage ack_msg;
- ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
-
- if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
- return false;
- }
- crash_event_ = reply.dump_request_handle;
- crash_generated_ = reply.dump_generated_handle;
- server_alive_ = reply.server_alive_handle;
- server_process_id_ = reply.pid;
-
- return true;
-}
-
-HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
- DWORD pipe_access,
- DWORD flags_attrs) {
- for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
- HANDLE pipe = CreateFile(pipe_name,
- pipe_access,
- 0,
- NULL,
- OPEN_EXISTING,
- flags_attrs,
- NULL);
- if (pipe != INVALID_HANDLE_VALUE) {
- return pipe;
- }
-
- // Cannot continue retrying if error is something other than
- // ERROR_PIPE_BUSY.
- if (GetLastError() != ERROR_PIPE_BUSY) {
- break;
- }
-
- // Cannot continue retrying if wait on pipe fails.
- if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
- break;
- }
- }
-
- return NULL;
-}
-
-bool CrashGenerationClient::ValidateResponse(
- const ProtocolMessage& msg) const {
- return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
- (msg.pid != 0) &&
- (msg.dump_request_handle != NULL) &&
- (msg.dump_generated_handle != NULL) &&
- (msg.server_alive_handle != NULL);
-}
-
-bool CrashGenerationClient::IsRegistered() const {
- return crash_event_ != NULL;
-}
-
-bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
- if (!IsRegistered()) {
- return false;
- }
-
- exception_pointers_ = ex_info;
- thread_id_ = GetCurrentThreadId();
-
- assert_info_.line = 0;
- assert_info_.type = 0;
- assert_info_.expression[0] = 0;
- assert_info_.file[0] = 0;
- assert_info_.function[0] = 0;
-
- return SignalCrashEventAndWait();
-}
-
-bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
- if (!IsRegistered()) {
- return false;
- }
-
- exception_pointers_ = NULL;
-
- if (assert_info) {
- memcpy(&assert_info_, assert_info, sizeof(assert_info_));
- } else {
- memset(&assert_info_, 0, sizeof(assert_info_));
- }
-
- thread_id_ = GetCurrentThreadId();
-
- return SignalCrashEventAndWait();
-}
-
-bool CrashGenerationClient::SignalCrashEventAndWait() {
- assert(crash_event_);
- assert(crash_generated_);
- assert(server_alive_);
-
- // Reset the dump generated event before signaling the crash
- // event so that the server can set the dump generated event
- // once it is done generating the event.
- if (!ResetEvent(crash_generated_)) {
- return false;
- }
-
- if (!SetEvent(crash_event_)) {
- return false;
- }
-
- HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
-
- DWORD result = WaitForMultipleObjects(kWaitEventCount,
- wait_handles,
- FALSE,
- kWaitForServerTimeoutMs);
-
- // Crash dump was successfully generated only if the server
- // signaled the crash generated event.
- return result == WAIT_OBJECT_0;
-}
-
-} // namespace google_breakpad
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/crash_generation_client.h"
+#include <cassert>
+#include "client/windows/common/ipc_protocol.h"
+
+namespace google_breakpad {
+
+const int kPipeBusyWaitTimeoutMs = 2000;
+
+#ifdef _DEBUG
+const DWORD kWaitForServerTimeoutMs = INFINITE;
+#else
+const DWORD kWaitForServerTimeoutMs = 15000;
+#endif
+
+const int kPipeConnectMaxAttempts = 2;
+
+const DWORD kPipeDesiredAccess = FILE_READ_DATA |
+ FILE_WRITE_DATA |
+ FILE_WRITE_ATTRIBUTES;
+
+const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
+ SECURITY_SQOS_PRESENT;
+
+const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
+
+const size_t kWaitEventCount = 2;
+
+// This function is orphan for production code. It can be used
+// for debugging to help repro some scenarios like the client
+// is slow in writing to the pipe after connecting, the client
+// is slow in reading from the pipe after writing, etc. The parameter
+// overlapped below is not used and it is present to match the signature
+// of this function to TransactNamedPipe Win32 API. Uncomment if needed
+// for debugging.
+/**
+static bool TransactNamedPipeDebugHelper(HANDLE pipe,
+ const void* in_buffer,
+ DWORD in_size,
+ void* out_buffer,
+ DWORD out_size,
+ DWORD* bytes_count,
+ LPOVERLAPPED) {
+ // Uncomment the next sleep to create a gap before writing
+ // to pipe.
+ // Sleep(5000);
+
+ if (!WriteFile(pipe,
+ in_buffer,
+ in_size,
+ bytes_count,
+ NULL)) {
+ return false;
+ }
+
+ // Uncomment the next sleep to create a gap between write
+ // and read.
+ // Sleep(5000);
+
+ return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
+}
+**/
+
+CrashGenerationClient::CrashGenerationClient(const wchar_t* pipe_name,
+ MINIDUMP_TYPE dump_type)
+ : pipe_name_(pipe_name),
+ dump_type_(dump_type),
+ thread_id_(0),
+ server_process_id_(0),
+ crash_event_(NULL),
+ crash_generated_(NULL),
+ server_alive_(NULL),
+ exception_pointers_(NULL) {
+ memset(&assert_info_, 0, sizeof(assert_info_));
+}
+
+CrashGenerationClient::~CrashGenerationClient() {
+ if (crash_event_) {
+ CloseHandle(crash_event_);
+ }
+
+ if (crash_generated_) {
+ CloseHandle(crash_generated_);
+ }
+
+ if (server_alive_) {
+ CloseHandle(server_alive_);
+ }
+}
+
+// Performs the registration step with the server process.
+// The registration step involves communicating with the server
+// via a named pipe. The client sends the following pieces of
+// data to the server:
+//
+// * Message tag indicating the client is requesting registration.
+// * Process id of the client process.
+// * Address of a DWORD variable in the client address space
+// that will contain the thread id of the client thread that
+// caused the crash.
+// * Address of a EXCEPTION_POINTERS* variable in the client
+// address space that will point to an instance of EXCEPTION_POINTERS
+// when the crash happens.
+// * Address of an instance of MDRawAssertionInfo that will contain
+// relevant information in case of non-exception crashes like assertion
+// failures and pure calls.
+//
+// In return the client expects the following information from the server:
+//
+// * Message tag indicating successful registration.
+// * Server process id.
+// * Handle to an object that client can signal to request dump
+// generation from the server.
+// * Handle to an object that client can wait on after requesting
+// dump generation for the server to finish dump generation.
+// * Handle to a mutex object that client can wait on to make sure
+// server is still alive.
+//
+// If any step of the expected behavior mentioned above fails, the
+// registration step is not considered successful and hence out-of-process
+// dump generation service is not available.
+//
+// Returns true if the registration is successful; false otherwise.
+bool CrashGenerationClient::Register() {
+ HANDLE pipe = ConnectToServer();
+ if (!pipe) {
+ return false;
+ }
+
+ bool success = RegisterClient(pipe);
+ CloseHandle(pipe);
+ return success;
+}
+
+HANDLE CrashGenerationClient::ConnectToServer() {
+ HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
+ kPipeDesiredAccess,
+ kPipeFlagsAndAttributes);
+ if (!pipe) {
+ return NULL;
+ }
+
+ DWORD mode = kPipeMode;
+ if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
+ CloseHandle(pipe);
+ pipe = NULL;
+ }
+
+ return pipe;
+}
+
+bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
+ ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
+ GetCurrentProcessId(),
+ dump_type_,
+ &thread_id_,
+ &exception_pointers_,
+ &assert_info_,
+ NULL,
+ NULL,
+ NULL);
+ ProtocolMessage reply;
+ DWORD bytes_count = 0;
+ // The call to TransactNamedPipe below can be changed to a call
+ // to TransactNamedPipeDebugHelper to help repro some scenarios.
+ // For details see comments for TransactNamedPipeDebugHelper.
+ if (!TransactNamedPipe(pipe,
+ &msg,
+ sizeof(msg),
+ &reply,
+ sizeof(ProtocolMessage),
+ &bytes_count,
+ NULL)) {
+ return false;
+ }
+
+ if (!ValidateResponse(reply)) {
+ return false;
+ }
+
+ ProtocolMessage ack_msg;
+ ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
+
+ if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
+ return false;
+ }
+ crash_event_ = reply.dump_request_handle;
+ crash_generated_ = reply.dump_generated_handle;
+ server_alive_ = reply.server_alive_handle;
+ server_process_id_ = reply.pid;
+
+ return true;
+}
+
+HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
+ DWORD pipe_access,
+ DWORD flags_attrs) {
+ for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
+ HANDLE pipe = CreateFile(pipe_name,
+ pipe_access,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ flags_attrs,
+ NULL);
+ if (pipe != INVALID_HANDLE_VALUE) {
+ return pipe;
+ }
+
+ // Cannot continue retrying if error is something other than
+ // ERROR_PIPE_BUSY.
+ if (GetLastError() != ERROR_PIPE_BUSY) {
+ break;
+ }
+
+ // Cannot continue retrying if wait on pipe fails.
+ if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+bool CrashGenerationClient::ValidateResponse(
+ const ProtocolMessage& msg) const {
+ return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
+ (msg.pid != 0) &&
+ (msg.dump_request_handle != NULL) &&
+ (msg.dump_generated_handle != NULL) &&
+ (msg.server_alive_handle != NULL);
+}
+
+bool CrashGenerationClient::IsRegistered() const {
+ return crash_event_ != NULL;
+}
+
+bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
+ if (!IsRegistered()) {
+ return false;
+ }
+
+ exception_pointers_ = ex_info;
+ thread_id_ = GetCurrentThreadId();
+
+ assert_info_.line = 0;
+ assert_info_.type = 0;
+ assert_info_.expression[0] = 0;
+ assert_info_.file[0] = 0;
+ assert_info_.function[0] = 0;
+
+ return SignalCrashEventAndWait();
+}
+
+bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
+ if (!IsRegistered()) {
+ return false;
+ }
+
+ exception_pointers_ = NULL;
+
+ if (assert_info) {
+ memcpy(&assert_info_, assert_info, sizeof(assert_info_));
+ } else {
+ memset(&assert_info_, 0, sizeof(assert_info_));
+ }
+
+ thread_id_ = GetCurrentThreadId();
+
+ return SignalCrashEventAndWait();
+}
+
+bool CrashGenerationClient::SignalCrashEventAndWait() {
+ assert(crash_event_);
+ assert(crash_generated_);
+ assert(server_alive_);
+
+ // Reset the dump generated event before signaling the crash
+ // event so that the server can set the dump generated event
+ // once it is done generating the event.
+ if (!ResetEvent(crash_generated_)) {
+ return false;
+ }
+
+ if (!SetEvent(crash_event_)) {
+ return false;
+ }
+
+ HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
+
+ DWORD result = WaitForMultipleObjects(kWaitEventCount,
+ wait_handles,
+ FALSE,
+ kWaitForServerTimeoutMs);
+
+ // Crash dump was successfully generated only if the server
+ // signaled the crash generated event.
+ return result == WAIT_OBJECT_0;
+}
+
+} // namespace google_breakpad
diff --git a/src/client/windows/crash_generation/crash_generation_client.h b/src/client/windows/crash_generation/crash_generation_client.h
index 01c9417a..fdec1c26 100644
--- a/src/client/windows/crash_generation/crash_generation_client.h
+++ b/src/client/windows/crash_generation/crash_generation_client.h
@@ -1,151 +1,151 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
-#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
-
-#include <windows.h>
-#include <dbghelp.h>
-#include <string>
-#include "client/windows/common/ipc_protocol.h"
-
-namespace google_breakpad {
-
-// Abstraction of client-side implementation of out of process
-// crash generation.
-//
-// The process that desires to have out-of-process crash dump
-// generation service can use this class in the following way:
-//
-// * Create an instance.
-// * Call Register method so that the client tries to register
-// with the server process and check the return value. If
-// registration is not successful, out-of-process crash dump
-// generation will not be available
-// * Request dump generation by calling either of the two
-// overloaded RequestDump methods - one in case of exceptions
-// and the other in case of assertion failures
-//
-// Note that it is the responsibility of the client code of
-// this class to set the unhandled exception filter with the
-// system by calling the SetUnhandledExceptionFilter function
-// and the client code should explicitly request dump generation.
-class CrashGenerationClient {
- public:
- CrashGenerationClient(const wchar_t* pipe_name,
- MINIDUMP_TYPE dump_type);
-
- ~CrashGenerationClient();
-
- // Registers the client process with the crash server.
- //
- // Returns true if the registration is successful; false otherwise.
- bool Register();
-
- // Requests the crash server to generate a dump with the given
- // exception information.
- //
- // Returns true if the dump was successful; false otherwise. Note that
- // if the registration step was not performed or it was not successful,
- // false will be returned.
- bool RequestDump(EXCEPTION_POINTERS* ex_info);
-
- // Requests the crash server to generate a dump with the given
- // assertion information.
- //
- // Returns true if the dump was successful; false otherwise. Note that
- // if the registration step was not performed or it was not successful,
- // false will be returned.
- bool RequestDump(MDRawAssertionInfo* assert_info);
-
- private:
- // Connects to the appropriate pipe and sets the pipe handle state.
- //
- // Returns the pipe handle if everything goes well; otherwise Returns NULL.
- HANDLE ConnectToServer();
-
- // Performs a handshake with the server over the given pipe which should be
- // already connected to the server.
- //
- // Returns true if handshake with the server was successful; false otherwise.
- bool RegisterClient(HANDLE pipe);
-
- // Validates the given server response.
- bool ValidateResponse(const ProtocolMessage& msg) const;
-
- // Returns true if the registration step succeeded; false otherwise.
- bool IsRegistered() const;
-
- // Connects to the given named pipe with given parameters.
- //
- // Returns true if the connection is successful; false otherwise.
- HANDLE ConnectToPipe(const wchar_t* pipe_name,
- DWORD pipe_access,
- DWORD flags_attrs);
-
- // Signals the crash event and wait for the server to generate crash.
- bool SignalCrashEventAndWait();
-
- // Pipe name to use to talk to server.
- std::wstring pipe_name_;
-
- // Type of dump to generate.
- MINIDUMP_TYPE dump_type_;
-
- // Event to signal in case of a crash.
- HANDLE crash_event_;
-
- // Handle to wait on after signaling a crash for the server
- // to finish generating crash dump.
- HANDLE crash_generated_;
-
- // Handle to a mutex that will become signaled with WAIT_ABANDONED
- // if the server process goes down.
- HANDLE server_alive_;
-
- // Server process id.
- DWORD server_process_id_;
-
- // Id of the thread that caused the crash.
- DWORD thread_id_;
-
- // Exception pointers for an exception crash.
- EXCEPTION_POINTERS* exception_pointers_;
-
- // Assertion info for an invalid parameter or pure call crash.
- MDRawAssertionInfo assert_info_;
-
- // Disable copy ctor and operator=.
- CrashGenerationClient(const CrashGenerationClient& crash_client);
- CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <string>
+#include "client/windows/common/ipc_protocol.h"
+
+namespace google_breakpad {
+
+// Abstraction of client-side implementation of out of process
+// crash generation.
+//
+// The process that desires to have out-of-process crash dump
+// generation service can use this class in the following way:
+//
+// * Create an instance.
+// * Call Register method so that the client tries to register
+// with the server process and check the return value. If
+// registration is not successful, out-of-process crash dump
+// generation will not be available
+// * Request dump generation by calling either of the two
+// overloaded RequestDump methods - one in case of exceptions
+// and the other in case of assertion failures
+//
+// Note that it is the responsibility of the client code of
+// this class to set the unhandled exception filter with the
+// system by calling the SetUnhandledExceptionFilter function
+// and the client code should explicitly request dump generation.
+class CrashGenerationClient {
+ public:
+ CrashGenerationClient(const wchar_t* pipe_name,
+ MINIDUMP_TYPE dump_type);
+
+ ~CrashGenerationClient();
+
+ // Registers the client process with the crash server.
+ //
+ // Returns true if the registration is successful; false otherwise.
+ bool Register();
+
+ // Requests the crash server to generate a dump with the given
+ // exception information.
+ //
+ // Returns true if the dump was successful; false otherwise. Note that
+ // if the registration step was not performed or it was not successful,
+ // false will be returned.
+ bool RequestDump(EXCEPTION_POINTERS* ex_info);
+
+ // Requests the crash server to generate a dump with the given
+ // assertion information.
+ //
+ // Returns true if the dump was successful; false otherwise. Note that
+ // if the registration step was not performed or it was not successful,
+ // false will be returned.
+ bool RequestDump(MDRawAssertionInfo* assert_info);
+
+ private:
+ // Connects to the appropriate pipe and sets the pipe handle state.
+ //
+ // Returns the pipe handle if everything goes well; otherwise Returns NULL.
+ HANDLE ConnectToServer();
+
+ // Performs a handshake with the server over the given pipe which should be
+ // already connected to the server.
+ //
+ // Returns true if handshake with the server was successful; false otherwise.
+ bool RegisterClient(HANDLE pipe);
+
+ // Validates the given server response.
+ bool ValidateResponse(const ProtocolMessage& msg) const;
+
+ // Returns true if the registration step succeeded; false otherwise.
+ bool IsRegistered() const;
+
+ // Connects to the given named pipe with given parameters.
+ //
+ // Returns true if the connection is successful; false otherwise.
+ HANDLE ConnectToPipe(const wchar_t* pipe_name,
+ DWORD pipe_access,
+ DWORD flags_attrs);
+
+ // Signals the crash event and wait for the server to generate crash.
+ bool SignalCrashEventAndWait();
+
+ // Pipe name to use to talk to server.
+ std::wstring pipe_name_;
+
+ // Type of dump to generate.
+ MINIDUMP_TYPE dump_type_;
+
+ // Event to signal in case of a crash.
+ HANDLE crash_event_;
+
+ // Handle to wait on after signaling a crash for the server
+ // to finish generating crash dump.
+ HANDLE crash_generated_;
+
+ // Handle to a mutex that will become signaled with WAIT_ABANDONED
+ // if the server process goes down.
+ HANDLE server_alive_;
+
+ // Server process id.
+ DWORD server_process_id_;
+
+ // Id of the thread that caused the crash.
+ DWORD thread_id_;
+
+ // Exception pointers for an exception crash.
+ EXCEPTION_POINTERS* exception_pointers_;
+
+ // Assertion info for an invalid parameter or pure call crash.
+ MDRawAssertionInfo assert_info_;
+
+ // Disable copy ctor and operator=.
+ CrashGenerationClient(const CrashGenerationClient& crash_client);
+ CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
diff --git a/src/client/windows/crash_generation/crash_generation_server.cc b/src/client/windows/crash_generation/crash_generation_server.cc
index 5409cc5a..c1929e50 100644
--- a/src/client/windows/crash_generation/crash_generation_server.cc
+++ b/src/client/windows/crash_generation/crash_generation_server.cc
@@ -1,823 +1,823 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "client/windows/crash_generation/crash_generation_server.h"
-#include <windows.h>
-#include <cassert>
-#include "client/windows/common/auto_critical_section.h"
-#include "processor/scoped_ptr.h"
-
-namespace google_breakpad {
-
-// Output buffer size.
-const size_t kOutBufferSize = 64;
-
-// Input buffer size.
-const size_t kInBufferSize = 64;
-
-// Access flags for the client on the dump request event.
-const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
-
-// Access flags for the client on the dump generated event.
-const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
- SYNCHRONIZE;
-
-// Access flags for the client on the mutex.
-const DWORD kMutexAccess = SYNCHRONIZE;
-
-// Attribute flags for the pipe.
-const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED;
-
-// Mode for the pipe.
-const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
- PIPE_READMODE_MESSAGE |
- PIPE_WAIT;
-
-// For pipe I/O, execute the callback in the wait thread itself,
-// since the callback does very little work. The callback executes
-// the code for one of the states of the server state machine and
-// the code for all of the states perform async I/O and hence
-// finish very quickly.
-const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
-
-// Dump request threads will, most likely, generate dumps. That may
-// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
-const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
- WT_EXECUTELONGFUNCTION;
-
-// Maximum delay during server shutdown if some work items
-// are still executing.
-const int kShutdownDelayMs = 10000;
-
-// Interval for each sleep during server shutdown.
-const int kShutdownSleepIntervalMs = 5;
-
-static bool IsClientRequestValid(const ProtocolMessage& msg) {
- return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
- msg.pid != 0 &&
- msg.thread_id != NULL &&
- msg.exception_pointers != NULL &&
- msg.assert_info != NULL;
-}
-
-CrashGenerationServer::CrashGenerationServer(
- const std::wstring& pipe_name,
- OnClientConnectedCallback connect_callback,
- void* connect_context,
- OnClientDumpRequestCallback dump_callback,
- void* dump_context,
- OnClientExitedCallback exit_callback,
- void* exit_context,
- bool generate_dumps,
- const std::wstring* dump_path)
- : pipe_name_(pipe_name),
- pipe_(NULL),
- pipe_wait_handle_(NULL),
- server_alive_handle_(NULL),
- connect_callback_(connect_callback),
- connect_context_(connect_context),
- dump_callback_(dump_callback),
- dump_context_(dump_context),
- exit_callback_(exit_callback),
- exit_context_(exit_context),
- generate_dumps_(generate_dumps),
- dump_generator_(NULL),
- server_state_(IPC_SERVER_STATE_INITIAL),
- shutting_down_(false),
- overlapped_(),
- client_info_(NULL),
- cleanup_item_count_(0) {
- InitializeCriticalSection(&clients_sync_);
-
- if (dump_path) {
- dump_generator_.reset(new MinidumpGenerator(*dump_path));
- }
-}
-
-CrashGenerationServer::~CrashGenerationServer() {
- // Indicate to existing threads that server is shutting down.
- shutting_down_ = true;
-
- // Unregister wait on the pipe.
- if (pipe_wait_handle_) {
- // Wait for already executing callbacks to finish.
- UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
- }
-
- // Close the pipe to avoid further client connections.
- if (pipe_) {
- CloseHandle(pipe_);
- }
-
- // Request all ClientInfo objects to unregister all waits.
- // New scope to hold the lock for the shortest time.
- {
- AutoCriticalSection lock(&clients_sync_);
-
- std::list<ClientInfo*>::iterator iter;
- for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
- ClientInfo* client_info = *iter;
- client_info->UnregisterWaits();
- }
- }
-
- // Now that all waits have been unregistered, wait for some time
- // for all pending work items to finish.
- int total_wait = 0;
- while (cleanup_item_count_ > 0) {
- Sleep(kShutdownSleepIntervalMs);
-
- total_wait += kShutdownSleepIntervalMs;
-
- if (total_wait >= kShutdownDelayMs) {
- break;
- }
- }
-
- // Clean up all the ClientInfo objects.
- // New scope to hold the lock for the shortest time.
- {
- AutoCriticalSection lock(&clients_sync_);
-
- std::list<ClientInfo*>::iterator iter;
- for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
- ClientInfo* client_info = *iter;
- delete client_info;
- }
- }
-
- if (server_alive_handle_) {
- // Release the mutex before closing the handle so that clients requesting
- // dumps wait for a long time for the server to generate a dump.
- ReleaseMutex(server_alive_handle_);
- CloseHandle(server_alive_handle_);
- }
-
- DeleteCriticalSection(&clients_sync_);
-}
-
-bool CrashGenerationServer::Start() {
- server_state_ = IPC_SERVER_STATE_INITIAL;
-
- server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
- if (!server_alive_handle_) {
- return false;
- }
-
- // Event to signal the client connection and pipe reads and writes.
- overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
- TRUE, // Manual reset.
- FALSE, // Initially signaled.
- NULL); // Name.
- if (!overlapped_.hEvent) {
- return false;
- }
-
- // Register a callback with the thread pool for the client connection.
- RegisterWaitForSingleObject(&pipe_wait_handle_,
- overlapped_.hEvent,
- OnPipeConnected,
- this,
- INFINITE,
- kPipeIOThreadFlags);
-
- pipe_ = CreateNamedPipe(pipe_name_.c_str(),
- kPipeAttr,
- kPipeMode,
- 1,
- kOutBufferSize,
- kInBufferSize,
- 0,
- NULL);
- if (!pipe_) {
- return false;
- }
-
- // Signal the event to start a separate thread to handle
- // client connections.
- return SetEvent(overlapped_.hEvent) != FALSE;
-}
-
-// If the server thread serving clients ever gets into the
-// ERROR state, reset the event, close the pipe and remain
-// in the error state forever. Error state means something
-// that we didn't account for has happened, and it's dangerous
-// to do anything unknowingly.
-void CrashGenerationServer::HandleErrorState() {
- assert(server_state_ == IPC_SERVER_STATE_ERROR);
-
- // If the server is shutting down anyway, don't clean up
- // here since shut down process will clean up.
- if (shutting_down_) {
- return;
- }
-
- if (pipe_wait_handle_) {
- UnregisterWait(pipe_wait_handle_);
- pipe_wait_handle_ = NULL;
- }
-
- if (pipe_) {
- CloseHandle(pipe_);
- pipe_ = NULL;
- }
-
- if (overlapped_.hEvent) {
- CloseHandle(overlapped_.hEvent);
- overlapped_.hEvent = NULL;
- }
-}
-
-// When the server thread serving clients is in the INITIAL state,
-// try to connect to the pipe asynchronously. If the connection
-// finishes synchronously, directly go into the CONNECTED state;
-// otherwise go into the CONNECTING state. For any problems, go
-// into the ERROR state.
-void CrashGenerationServer::HandleInitialState() {
- assert(server_state_ == IPC_SERVER_STATE_INITIAL);
-
- if (!ResetEvent(overlapped_.hEvent)) {
- server_state_ = IPC_SERVER_STATE_ERROR;
- return;
- }
-
- bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
-
- // From MSDN, it is not clear that when ConnectNamedPipe is used
- // in an overlapped mode, will it ever return non-zero value, and
- // if so, in what cases.
- assert(!success);
-
- DWORD error_code = GetLastError();
- switch (error_code) {
- case ERROR_IO_PENDING:
- server_state_ = IPC_SERVER_STATE_CONNECTING;
- break;
-
- case ERROR_PIPE_CONNECTED:
- if (SetEvent(overlapped_.hEvent)) {
- server_state_ = IPC_SERVER_STATE_CONNECTED;
- } else {
- server_state_ = IPC_SERVER_STATE_ERROR;
- }
- break;
-
- default:
- server_state_ = IPC_SERVER_STATE_ERROR;
- break;
- }
-}
-
-// When the server thread serving the clients is in the CONNECTING state,
-// try to get the result of the asynchronous connection request using
-// the OVERLAPPED object. If the result indicates the connection is done,
-// go into the CONNECTED state. If the result indicates I/O is still
-// INCOMPLETE, remain in the CONNECTING state. For any problems,
-// go into the DISCONNECTING state.
-void CrashGenerationServer::HandleConnectingState() {
- assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
-
- DWORD bytes_count = 0;
- bool success = GetOverlappedResult(pipe_,
- &overlapped_,
- &bytes_count,
- FALSE) != FALSE;
-
- if (success) {
- server_state_ = IPC_SERVER_STATE_CONNECTED;
- return;
- }
-
- if (GetLastError() != ERROR_IO_INCOMPLETE) {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- }
-}
-
-// When the server thread serving the clients is in the CONNECTED state,
-// try to issue an asynchronous read from the pipe. If read completes
-// synchronously or if I/O is pending then go into the READING state.
-// For any problems, go into the DISCONNECTING state.
-void CrashGenerationServer::HandleConnectedState() {
- assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
-
- DWORD bytes_count = 0;
- memset(&msg_, 0, sizeof(msg_));
- bool success = ReadFile(pipe_,
- &msg_,
- sizeof(msg_),
- &bytes_count,
- &overlapped_) != FALSE;
-
- // Note that the asynchronous read issued above can finish before the
- // code below executes. But, it is okay to change state after issuing
- // the asynchronous read. This is because even if the asynchronous read
- // is done, the callback for it would not be executed until the current
- // thread finishes its execution.
- if (success || GetLastError() == ERROR_IO_PENDING) {
- server_state_ = IPC_SERVER_STATE_READING;
- } else {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- }
-}
-
-// When the server thread serving the clients is in the READING state,
-// try to get the result of the async read. If async read is done,
-// go into the READ_DONE state. For any problems, go into the
-// DISCONNECTING state.
-void CrashGenerationServer::HandleReadingState() {
- assert(server_state_ == IPC_SERVER_STATE_READING);
-
- DWORD bytes_count = 0;
- bool success = GetOverlappedResult(pipe_,
- &overlapped_,
- &bytes_count,
- FALSE) != FALSE;
-
- if (success && bytes_count == sizeof(ProtocolMessage)) {
- server_state_ = IPC_SERVER_STATE_READ_DONE;
- return;
- }
-
- DWORD error_code;
- error_code = GetLastError();
-
- // We should never get an I/O incomplete since we should not execute this
- // unless the Read has finished and the overlapped event is signaled. If
- // we do get INCOMPLETE, we have a bug in our code.
- assert(error_code != ERROR_IO_INCOMPLETE);
-
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
-}
-
-// When the server thread serving the client is in the READ_DONE state,
-// validate the client's request message, register the client by
-// creating appropriate objects and prepare the response. Then try to
-// write the response to the pipe asynchronously. If that succeeds,
-// go into the WRITING state. For any problems, go into the DISCONNECTING
-// state.
-void CrashGenerationServer::HandleReadDoneState() {
- assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
-
- if (!IsClientRequestValid(msg_)) {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- return;
- }
-
- scoped_ptr<ClientInfo> client_info(
- new ClientInfo(this,
- msg_.pid,
- msg_.dump_type,
- msg_.thread_id,
- msg_.exception_pointers,
- msg_.assert_info));
-
- if (!client_info->Initialize()) {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- return;
- }
-
- if (!RespondToClient(client_info.get())) {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- return;
- }
-
- // Note that the asynchronous write issued by RespondToClient function
- // can finish before the code below executes. But it is okay to change
- // state after issuing the asynchronous write. This is because even if
- // the asynchronous write is done, the callback for it would not be
- // executed until the current thread finishes its execution.
- server_state_ = IPC_SERVER_STATE_WRITING;
- client_info_ = client_info.release();
-}
-
-// When the server thread serving the clients is in the WRITING state,
-// try to get the result of the async write. If the async write is done,
-// go into the WRITE_DONE state. For any problems, go into the
-// DISONNECTING state.
-void CrashGenerationServer::HandleWritingState() {
- assert(server_state_ == IPC_SERVER_STATE_WRITING);
-
- DWORD bytes_count = 0;
- bool success = GetOverlappedResult(pipe_,
- &overlapped_,
- &bytes_count,
- FALSE) != FALSE;
-
- if (success) {
- server_state_ = IPC_SERVER_STATE_WRITE_DONE;
- return;
- }
-
- DWORD error_code;
- error_code = GetLastError();
-
- // We should never get an I/O incomplete since we should not execute this
- // unless the Write has finished and the overlapped event is signaled. If
- // we do get INCOMPLETE, we have a bug in our code.
- assert(error_code != ERROR_IO_INCOMPLETE);
-
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
-}
-
-// When the server thread serving the clients is in the WRITE_DONE state,
-// try to issue an async read on the pipe. If the read completes synchronously
-// or if I/O is still pending then go into the READING_ACK state. For any
-// issues, go into the DISCONNECTING state.
-void CrashGenerationServer::HandleWriteDoneState() {
- assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
-
- server_state_ = IPC_SERVER_STATE_READING_ACK;
-
- DWORD bytes_count = 0;
- bool success = ReadFile(pipe_,
- &msg_,
- sizeof(msg_),
- &bytes_count,
- &overlapped_) != FALSE;
-
- if (success) {
- return;
- }
-
- DWORD error_code = GetLastError();
-
- if (error_code != ERROR_IO_PENDING) {
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
- }
-}
-
-// When the server thread serving the clients is in the READING_ACK state,
-// try to get result of async read. Go into the DISCONNECTING state.
-void CrashGenerationServer::HandleReadingAckState() {
- assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
-
- DWORD bytes_count = 0;
- bool success = GetOverlappedResult(pipe_,
- &overlapped_,
- &bytes_count,
- FALSE) != FALSE;
-
- if (success) {
- // The connection handshake with the client is now complete; perform
- // the callback.
- if (connect_callback_) {
- connect_callback_(connect_context_, client_info_);
- }
- } else {
- DWORD error_code;
- error_code = GetLastError();
-
- // We should never get an I/O incomplete since we should not execute this
- // unless the Read has finished and the overlapped event is signaled. If
- // we do get INCOMPLETE, we have a bug in our code.
- assert(error_code != ERROR_IO_INCOMPLETE);
- }
-
- server_state_ = IPC_SERVER_STATE_DISCONNECTING;
-}
-
-// When the server thread serving the client is in the DISCONNECTING state,
-// disconnect from the pipe and reset the event. If anything fails, go into
-// the ERROR state. If it goes well, go into the INITIAL state and set the
-// event to start all over again.
-void CrashGenerationServer::HandleDisconnectingState() {
- assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
-
- // Done serving the client.
- client_info_ = NULL;
-
- overlapped_.Internal = NULL;
- overlapped_.InternalHigh = NULL;
- overlapped_.Offset = 0;
- overlapped_.OffsetHigh = 0;
- overlapped_.Pointer = NULL;
-
- if (!ResetEvent(overlapped_.hEvent)) {
- server_state_ = IPC_SERVER_STATE_ERROR;
- return;
- }
-
- if (!DisconnectNamedPipe(pipe_)) {
- server_state_ = IPC_SERVER_STATE_ERROR;
- return;
- }
-
- // If the server is shutting down do not connect to the
- // next client.
- if (shutting_down_) {
- return;
- }
-
- server_state_ = IPC_SERVER_STATE_INITIAL;
- if (!SetEvent(overlapped_.hEvent)) {
- server_state_ = IPC_SERVER_STATE_ERROR;
- }
-}
-
-bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
- ProtocolMessage* reply) const {
- reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
- reply->pid = GetCurrentProcessId();
-
- if (CreateClientHandles(client_info, reply)) {
- return true;
- }
-
- if (reply->dump_request_handle) {
- CloseHandle(reply->dump_request_handle);
- }
-
- if (reply->dump_generated_handle) {
- CloseHandle(reply->dump_generated_handle);
- }
-
- if (reply->server_alive_handle) {
- CloseHandle(reply->server_alive_handle);
- }
-
- return false;
-}
-
-bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
- ProtocolMessage* reply) const {
- HANDLE current_process = GetCurrentProcess();
- if (!DuplicateHandle(current_process,
- client_info.dump_requested_handle(),
- client_info.process_handle(),
- &reply->dump_request_handle,
- kDumpRequestEventAccess,
- FALSE,
- 0)) {
- return false;
- }
-
- if (!DuplicateHandle(current_process,
- client_info.dump_generated_handle(),
- client_info.process_handle(),
- &reply->dump_generated_handle,
- kDumpGeneratedEventAccess,
- FALSE,
- 0)) {
- return false;
- }
-
- if (!DuplicateHandle(current_process,
- server_alive_handle_,
- client_info.process_handle(),
- &reply->server_alive_handle,
- kMutexAccess,
- FALSE,
- 0)) {
- return false;
- }
-
- return true;
-}
-
-bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
- ProtocolMessage reply;
- if (!PrepareReply(*client_info, &reply)) {
- return false;
- }
-
- if (!AddClient(client_info)) {
- return false;
- }
-
- DWORD bytes_count = 0;
- bool success = WriteFile(pipe_,
- &reply,
- sizeof(reply),
- &bytes_count,
- &overlapped_) != FALSE;
-
- return success || GetLastError() == ERROR_IO_PENDING;
-}
-
-// The server thread servicing the clients runs this method. The method
-// implements the state machine described in ReadMe.txt along with the
-// helper methods HandleXXXState.
-void CrashGenerationServer::HandleConnectionRequest() {
- switch (server_state_) {
- case IPC_SERVER_STATE_ERROR:
- HandleErrorState();
- break;
-
- case IPC_SERVER_STATE_INITIAL:
- HandleInitialState();
- break;
-
- case IPC_SERVER_STATE_CONNECTING:
- HandleConnectingState();
- break;
-
- case IPC_SERVER_STATE_CONNECTED:
- HandleConnectedState();
- break;
-
- case IPC_SERVER_STATE_READING:
- HandleReadingState();
- break;
-
- case IPC_SERVER_STATE_READ_DONE:
- HandleReadDoneState();
- break;
-
- case IPC_SERVER_STATE_WRITING:
- HandleWritingState();
- break;
-
- case IPC_SERVER_STATE_WRITE_DONE:
- HandleWriteDoneState();
- break;
-
- case IPC_SERVER_STATE_READING_ACK:
- HandleReadingAckState();
- break;
-
- case IPC_SERVER_STATE_DISCONNECTING:
- HandleDisconnectingState();
- break;
-
- default:
- assert(false);
- // This indicates that we added one more state without
- // adding handling code.
- server_state_ = IPC_SERVER_STATE_ERROR;
- break;
- }
-}
-
-bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
- HANDLE request_wait_handle = NULL;
- if (!RegisterWaitForSingleObject(&request_wait_handle,
- client_info->dump_requested_handle(),
- OnDumpRequest,
- client_info,
- INFINITE,
- kDumpRequestThreadFlags)) {
- return false;
- }
-
- client_info->set_dump_request_wait_handle(request_wait_handle);
-
- // OnClientEnd will be called when the client process terminates.
- HANDLE process_wait_handle = NULL;
- if (!RegisterWaitForSingleObject(&process_wait_handle,
- client_info->process_handle(),
- OnClientEnd,
- client_info,
- INFINITE,
- WT_EXECUTEONLYONCE)) {
- return false;
- }
-
- client_info->set_process_exit_wait_handle(process_wait_handle);
-
- // New scope to hold the lock for the shortest time.
- {
- AutoCriticalSection lock(&clients_sync_);
- clients_.push_back(client_info);
- }
-
- return true;
-}
-
-// static
-void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
- assert (context);
-
- CrashGenerationServer* obj =
- reinterpret_cast<CrashGenerationServer*>(context);
- obj->HandleConnectionRequest();
-}
-
-// static
-void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
- assert(context);
- ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
-
- CrashGenerationServer* crash_server = client_info->crash_server();
- assert(crash_server);
- crash_server->HandleDumpRequest(*client_info);
-
- ResetEvent(client_info->dump_requested_handle());
-}
-
-// static
-void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
- assert(context);
- ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
-
- CrashGenerationServer* crash_server = client_info->crash_server();
- assert(crash_server);
-
- InterlockedIncrement(&crash_server->cleanup_item_count_);
-
- if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {
- InterlockedDecrement(&crash_server->cleanup_item_count_);
- }
-}
-
-// static
-DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {
- assert(context);
- ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
-
- CrashGenerationServer* crash_server = client_info->crash_server();
- assert(crash_server);
-
- if (crash_server->exit_callback_) {
- crash_server->exit_callback_(crash_server->exit_context_, client_info);
- }
-
- crash_server->DoCleanup(client_info);
-
- InterlockedDecrement(&crash_server->cleanup_item_count_);
- return 0;
-}
-
-void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
- assert(client_info);
-
- // Start a new scope to release lock automatically.
- {
- AutoCriticalSection lock(&clients_sync_);
- clients_.remove(client_info);
- }
-
- delete client_info;
-}
-
-void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
- // Generate the dump only if it's explicitly requested by the
- // server application; otherwise the server might want to generate
- // dump in the callback.
- if (generate_dumps_) {
- if (!GenerateDump(client_info)) {
- return;
- }
- }
-
- if (dump_callback_) {
- dump_callback_(dump_context_, &client_info);
- }
-
- SetEvent(client_info.dump_generated_handle());
-}
-
-bool CrashGenerationServer::GenerateDump(const ClientInfo& client) {
- assert(client.pid() != 0);
- assert(client.process_handle());
-
- // We have to get the address of EXCEPTION_INFORMATION from
- // the client process address space.
- EXCEPTION_POINTERS* client_ex_info = NULL;
- if (!client.GetClientExceptionInfo(&client_ex_info)) {
- return false;
- }
-
- DWORD client_thread_id = 0;
- if (!client.GetClientThreadId(&client_thread_id)) {
- return false;
- }
-
- return dump_generator_->WriteMinidump(client.process_handle(),
- client.pid(),
- client_thread_id,
- GetCurrentThreadId(),
- client_ex_info,
- client.assert_info(),
- client.dump_type(),
- true);
-}
-
-} // namespace google_breakpad
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/crash_generation_server.h"
+#include <windows.h>
+#include <cassert>
+#include "client/windows/common/auto_critical_section.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+// Output buffer size.
+const size_t kOutBufferSize = 64;
+
+// Input buffer size.
+const size_t kInBufferSize = 64;
+
+// Access flags for the client on the dump request event.
+const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
+
+// Access flags for the client on the dump generated event.
+const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
+ SYNCHRONIZE;
+
+// Access flags for the client on the mutex.
+const DWORD kMutexAccess = SYNCHRONIZE;
+
+// Attribute flags for the pipe.
+const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED;
+
+// Mode for the pipe.
+const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT;
+
+// For pipe I/O, execute the callback in the wait thread itself,
+// since the callback does very little work. The callback executes
+// the code for one of the states of the server state machine and
+// the code for all of the states perform async I/O and hence
+// finish very quickly.
+const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
+
+// Dump request threads will, most likely, generate dumps. That may
+// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
+const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
+ WT_EXECUTELONGFUNCTION;
+
+// Maximum delay during server shutdown if some work items
+// are still executing.
+const int kShutdownDelayMs = 10000;
+
+// Interval for each sleep during server shutdown.
+const int kShutdownSleepIntervalMs = 5;
+
+static bool IsClientRequestValid(const ProtocolMessage& msg) {
+ return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
+ msg.pid != 0 &&
+ msg.thread_id != NULL &&
+ msg.exception_pointers != NULL &&
+ msg.assert_info != NULL;
+}
+
+CrashGenerationServer::CrashGenerationServer(
+ const std::wstring& pipe_name,
+ OnClientConnectedCallback connect_callback,
+ void* connect_context,
+ OnClientDumpRequestCallback dump_callback,
+ void* dump_context,
+ OnClientExitedCallback exit_callback,
+ void* exit_context,
+ bool generate_dumps,
+ const std::wstring* dump_path)
+ : pipe_name_(pipe_name),
+ pipe_(NULL),
+ pipe_wait_handle_(NULL),
+ server_alive_handle_(NULL),
+ connect_callback_(connect_callback),
+ connect_context_(connect_context),
+ dump_callback_(dump_callback),
+ dump_context_(dump_context),
+ exit_callback_(exit_callback),
+ exit_context_(exit_context),
+ generate_dumps_(generate_dumps),
+ dump_generator_(NULL),
+ server_state_(IPC_SERVER_STATE_INITIAL),
+ shutting_down_(false),
+ overlapped_(),
+ client_info_(NULL),
+ cleanup_item_count_(0) {
+ InitializeCriticalSection(&clients_sync_);
+
+ if (dump_path) {
+ dump_generator_.reset(new MinidumpGenerator(*dump_path));
+ }
+}
+
+CrashGenerationServer::~CrashGenerationServer() {
+ // Indicate to existing threads that server is shutting down.
+ shutting_down_ = true;
+
+ // Unregister wait on the pipe.
+ if (pipe_wait_handle_) {
+ // Wait for already executing callbacks to finish.
+ UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
+ }
+
+ // Close the pipe to avoid further client connections.
+ if (pipe_) {
+ CloseHandle(pipe_);
+ }
+
+ // Request all ClientInfo objects to unregister all waits.
+ // New scope to hold the lock for the shortest time.
+ {
+ AutoCriticalSection lock(&clients_sync_);
+
+ std::list<ClientInfo*>::iterator iter;
+ for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+ ClientInfo* client_info = *iter;
+ client_info->UnregisterWaits();
+ }
+ }
+
+ // Now that all waits have been unregistered, wait for some time
+ // for all pending work items to finish.
+ int total_wait = 0;
+ while (cleanup_item_count_ > 0) {
+ Sleep(kShutdownSleepIntervalMs);
+
+ total_wait += kShutdownSleepIntervalMs;
+
+ if (total_wait >= kShutdownDelayMs) {
+ break;
+ }
+ }
+
+ // Clean up all the ClientInfo objects.
+ // New scope to hold the lock for the shortest time.
+ {
+ AutoCriticalSection lock(&clients_sync_);
+
+ std::list<ClientInfo*>::iterator iter;
+ for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+ ClientInfo* client_info = *iter;
+ delete client_info;
+ }
+ }
+
+ if (server_alive_handle_) {
+ // Release the mutex before closing the handle so that clients requesting
+ // dumps wait for a long time for the server to generate a dump.
+ ReleaseMutex(server_alive_handle_);
+ CloseHandle(server_alive_handle_);
+ }
+
+ DeleteCriticalSection(&clients_sync_);
+}
+
+bool CrashGenerationServer::Start() {
+ server_state_ = IPC_SERVER_STATE_INITIAL;
+
+ server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
+ if (!server_alive_handle_) {
+ return false;
+ }
+
+ // Event to signal the client connection and pipe reads and writes.
+ overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
+ TRUE, // Manual reset.
+ FALSE, // Initially signaled.
+ NULL); // Name.
+ if (!overlapped_.hEvent) {
+ return false;
+ }
+
+ // Register a callback with the thread pool for the client connection.
+ RegisterWaitForSingleObject(&pipe_wait_handle_,
+ overlapped_.hEvent,
+ OnPipeConnected,
+ this,
+ INFINITE,
+ kPipeIOThreadFlags);
+
+ pipe_ = CreateNamedPipe(pipe_name_.c_str(),
+ kPipeAttr,
+ kPipeMode,
+ 1,
+ kOutBufferSize,
+ kInBufferSize,
+ 0,
+ NULL);
+ if (!pipe_) {
+ return false;
+ }
+
+ // Signal the event to start a separate thread to handle
+ // client connections.
+ return SetEvent(overlapped_.hEvent) != FALSE;
+}
+
+// If the server thread serving clients ever gets into the
+// ERROR state, reset the event, close the pipe and remain
+// in the error state forever. Error state means something
+// that we didn't account for has happened, and it's dangerous
+// to do anything unknowingly.
+void CrashGenerationServer::HandleErrorState() {
+ assert(server_state_ == IPC_SERVER_STATE_ERROR);
+
+ // If the server is shutting down anyway, don't clean up
+ // here since shut down process will clean up.
+ if (shutting_down_) {
+ return;
+ }
+
+ if (pipe_wait_handle_) {
+ UnregisterWait(pipe_wait_handle_);
+ pipe_wait_handle_ = NULL;
+ }
+
+ if (pipe_) {
+ CloseHandle(pipe_);
+ pipe_ = NULL;
+ }
+
+ if (overlapped_.hEvent) {
+ CloseHandle(overlapped_.hEvent);
+ overlapped_.hEvent = NULL;
+ }
+}
+
+// When the server thread serving clients is in the INITIAL state,
+// try to connect to the pipe asynchronously. If the connection
+// finishes synchronously, directly go into the CONNECTED state;
+// otherwise go into the CONNECTING state. For any problems, go
+// into the ERROR state.
+void CrashGenerationServer::HandleInitialState() {
+ assert(server_state_ == IPC_SERVER_STATE_INITIAL);
+
+ if (!ResetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ return;
+ }
+
+ bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
+
+ // From MSDN, it is not clear that when ConnectNamedPipe is used
+ // in an overlapped mode, will it ever return non-zero value, and
+ // if so, in what cases.
+ assert(!success);
+
+ DWORD error_code = GetLastError();
+ switch (error_code) {
+ case ERROR_IO_PENDING:
+ server_state_ = IPC_SERVER_STATE_CONNECTING;
+ break;
+
+ case ERROR_PIPE_CONNECTED:
+ if (SetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_CONNECTED;
+ } else {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ }
+ break;
+
+ default:
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ break;
+ }
+}
+
+// When the server thread serving the clients is in the CONNECTING state,
+// try to get the result of the asynchronous connection request using
+// the OVERLAPPED object. If the result indicates the connection is done,
+// go into the CONNECTED state. If the result indicates I/O is still
+// INCOMPLETE, remain in the CONNECTING state. For any problems,
+// go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectingState() {
+ assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+
+ if (success) {
+ server_state_ = IPC_SERVER_STATE_CONNECTED;
+ return;
+ }
+
+ if (GetLastError() != ERROR_IO_INCOMPLETE) {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ }
+}
+
+// When the server thread serving the clients is in the CONNECTED state,
+// try to issue an asynchronous read from the pipe. If read completes
+// synchronously or if I/O is pending then go into the READING state.
+// For any problems, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectedState() {
+ assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
+
+ DWORD bytes_count = 0;
+ memset(&msg_, 0, sizeof(msg_));
+ bool success = ReadFile(pipe_,
+ &msg_,
+ sizeof(msg_),
+ &bytes_count,
+ &overlapped_) != FALSE;
+
+ // Note that the asynchronous read issued above can finish before the
+ // code below executes. But, it is okay to change state after issuing
+ // the asynchronous read. This is because even if the asynchronous read
+ // is done, the callback for it would not be executed until the current
+ // thread finishes its execution.
+ if (success || GetLastError() == ERROR_IO_PENDING) {
+ server_state_ = IPC_SERVER_STATE_READING;
+ } else {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ }
+}
+
+// When the server thread serving the clients is in the READING state,
+// try to get the result of the async read. If async read is done,
+// go into the READ_DONE state. For any problems, go into the
+// DISCONNECTING state.
+void CrashGenerationServer::HandleReadingState() {
+ assert(server_state_ == IPC_SERVER_STATE_READING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+
+ if (success && bytes_count == sizeof(ProtocolMessage)) {
+ server_state_ = IPC_SERVER_STATE_READ_DONE;
+ return;
+ }
+
+ DWORD error_code;
+ error_code = GetLastError();
+
+ // We should never get an I/O incomplete since we should not execute this
+ // unless the Read has finished and the overlapped event is signaled. If
+ // we do get INCOMPLETE, we have a bug in our code.
+ assert(error_code != ERROR_IO_INCOMPLETE);
+
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the client is in the READ_DONE state,
+// validate the client's request message, register the client by
+// creating appropriate objects and prepare the response. Then try to
+// write the response to the pipe asynchronously. If that succeeds,
+// go into the WRITING state. For any problems, go into the DISCONNECTING
+// state.
+void CrashGenerationServer::HandleReadDoneState() {
+ assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
+
+ if (!IsClientRequestValid(msg_)) {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ return;
+ }
+
+ scoped_ptr<ClientInfo> client_info(
+ new ClientInfo(this,
+ msg_.pid,
+ msg_.dump_type,
+ msg_.thread_id,
+ msg_.exception_pointers,
+ msg_.assert_info));
+
+ if (!client_info->Initialize()) {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ return;
+ }
+
+ if (!RespondToClient(client_info.get())) {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ return;
+ }
+
+ // Note that the asynchronous write issued by RespondToClient function
+ // can finish before the code below executes. But it is okay to change
+ // state after issuing the asynchronous write. This is because even if
+ // the asynchronous write is done, the callback for it would not be
+ // executed until the current thread finishes its execution.
+ server_state_ = IPC_SERVER_STATE_WRITING;
+ client_info_ = client_info.release();
+}
+
+// When the server thread serving the clients is in the WRITING state,
+// try to get the result of the async write. If the async write is done,
+// go into the WRITE_DONE state. For any problems, go into the
+// DISONNECTING state.
+void CrashGenerationServer::HandleWritingState() {
+ assert(server_state_ == IPC_SERVER_STATE_WRITING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+
+ if (success) {
+ server_state_ = IPC_SERVER_STATE_WRITE_DONE;
+ return;
+ }
+
+ DWORD error_code;
+ error_code = GetLastError();
+
+ // We should never get an I/O incomplete since we should not execute this
+ // unless the Write has finished and the overlapped event is signaled. If
+ // we do get INCOMPLETE, we have a bug in our code.
+ assert(error_code != ERROR_IO_INCOMPLETE);
+
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the clients is in the WRITE_DONE state,
+// try to issue an async read on the pipe. If the read completes synchronously
+// or if I/O is still pending then go into the READING_ACK state. For any
+// issues, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleWriteDoneState() {
+ assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
+
+ server_state_ = IPC_SERVER_STATE_READING_ACK;
+
+ DWORD bytes_count = 0;
+ bool success = ReadFile(pipe_,
+ &msg_,
+ sizeof(msg_),
+ &bytes_count,
+ &overlapped_) != FALSE;
+
+ if (success) {
+ return;
+ }
+
+ DWORD error_code = GetLastError();
+
+ if (error_code != ERROR_IO_PENDING) {
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+ }
+}
+
+// When the server thread serving the clients is in the READING_ACK state,
+// try to get result of async read. Go into the DISCONNECTING state.
+void CrashGenerationServer::HandleReadingAckState() {
+ assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+
+ if (success) {
+ // The connection handshake with the client is now complete; perform
+ // the callback.
+ if (connect_callback_) {
+ connect_callback_(connect_context_, client_info_);
+ }
+ } else {
+ DWORD error_code;
+ error_code = GetLastError();
+
+ // We should never get an I/O incomplete since we should not execute this
+ // unless the Read has finished and the overlapped event is signaled. If
+ // we do get INCOMPLETE, we have a bug in our code.
+ assert(error_code != ERROR_IO_INCOMPLETE);
+ }
+
+ server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the client is in the DISCONNECTING state,
+// disconnect from the pipe and reset the event. If anything fails, go into
+// the ERROR state. If it goes well, go into the INITIAL state and set the
+// event to start all over again.
+void CrashGenerationServer::HandleDisconnectingState() {
+ assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
+
+ // Done serving the client.
+ client_info_ = NULL;
+
+ overlapped_.Internal = NULL;
+ overlapped_.InternalHigh = NULL;
+ overlapped_.Offset = 0;
+ overlapped_.OffsetHigh = 0;
+ overlapped_.Pointer = NULL;
+
+ if (!ResetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ return;
+ }
+
+ if (!DisconnectNamedPipe(pipe_)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ return;
+ }
+
+ // If the server is shutting down do not connect to the
+ // next client.
+ if (shutting_down_) {
+ return;
+ }
+
+ server_state_ = IPC_SERVER_STATE_INITIAL;
+ if (!SetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ }
+}
+
+bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
+ ProtocolMessage* reply) const {
+ reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
+ reply->pid = GetCurrentProcessId();
+
+ if (CreateClientHandles(client_info, reply)) {
+ return true;
+ }
+
+ if (reply->dump_request_handle) {
+ CloseHandle(reply->dump_request_handle);
+ }
+
+ if (reply->dump_generated_handle) {
+ CloseHandle(reply->dump_generated_handle);
+ }
+
+ if (reply->server_alive_handle) {
+ CloseHandle(reply->server_alive_handle);
+ }
+
+ return false;
+}
+
+bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
+ ProtocolMessage* reply) const {
+ HANDLE current_process = GetCurrentProcess();
+ if (!DuplicateHandle(current_process,
+ client_info.dump_requested_handle(),
+ client_info.process_handle(),
+ &reply->dump_request_handle,
+ kDumpRequestEventAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ if (!DuplicateHandle(current_process,
+ client_info.dump_generated_handle(),
+ client_info.process_handle(),
+ &reply->dump_generated_handle,
+ kDumpGeneratedEventAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ if (!DuplicateHandle(current_process,
+ server_alive_handle_,
+ client_info.process_handle(),
+ &reply->server_alive_handle,
+ kMutexAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
+ ProtocolMessage reply;
+ if (!PrepareReply(*client_info, &reply)) {
+ return false;
+ }
+
+ if (!AddClient(client_info)) {
+ return false;
+ }
+
+ DWORD bytes_count = 0;
+ bool success = WriteFile(pipe_,
+ &reply,
+ sizeof(reply),
+ &bytes_count,
+ &overlapped_) != FALSE;
+
+ return success || GetLastError() == ERROR_IO_PENDING;
+}
+
+// The server thread servicing the clients runs this method. The method
+// implements the state machine described in ReadMe.txt along with the
+// helper methods HandleXXXState.
+void CrashGenerationServer::HandleConnectionRequest() {
+ switch (server_state_) {
+ case IPC_SERVER_STATE_ERROR:
+ HandleErrorState();
+ break;
+
+ case IPC_SERVER_STATE_INITIAL:
+ HandleInitialState();
+ break;
+
+ case IPC_SERVER_STATE_CONNECTING:
+ HandleConnectingState();
+ break;
+
+ case IPC_SERVER_STATE_CONNECTED:
+ HandleConnectedState();
+ break;
+
+ case IPC_SERVER_STATE_READING:
+ HandleReadingState();
+ break;
+
+ case IPC_SERVER_STATE_READ_DONE:
+ HandleReadDoneState();
+ break;
+
+ case IPC_SERVER_STATE_WRITING:
+ HandleWritingState();
+ break;
+
+ case IPC_SERVER_STATE_WRITE_DONE:
+ HandleWriteDoneState();
+ break;
+
+ case IPC_SERVER_STATE_READING_ACK:
+ HandleReadingAckState();
+ break;
+
+ case IPC_SERVER_STATE_DISCONNECTING:
+ HandleDisconnectingState();
+ break;
+
+ default:
+ assert(false);
+ // This indicates that we added one more state without
+ // adding handling code.
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ break;
+ }
+}
+
+bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
+ HANDLE request_wait_handle = NULL;
+ if (!RegisterWaitForSingleObject(&request_wait_handle,
+ client_info->dump_requested_handle(),
+ OnDumpRequest,
+ client_info,
+ INFINITE,
+ kDumpRequestThreadFlags)) {
+ return false;
+ }
+
+ client_info->set_dump_request_wait_handle(request_wait_handle);
+
+ // OnClientEnd will be called when the client process terminates.
+ HANDLE process_wait_handle = NULL;
+ if (!RegisterWaitForSingleObject(&process_wait_handle,
+ client_info->process_handle(),
+ OnClientEnd,
+ client_info,
+ INFINITE,
+ WT_EXECUTEONLYONCE)) {
+ return false;
+ }
+
+ client_info->set_process_exit_wait_handle(process_wait_handle);
+
+ // New scope to hold the lock for the shortest time.
+ {
+ AutoCriticalSection lock(&clients_sync_);
+ clients_.push_back(client_info);
+ }
+
+ return true;
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
+ assert (context);
+
+ CrashGenerationServer* obj =
+ reinterpret_cast<CrashGenerationServer*>(context);
+ obj->HandleConnectionRequest();
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
+ assert(context);
+ ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+ CrashGenerationServer* crash_server = client_info->crash_server();
+ assert(crash_server);
+ crash_server->HandleDumpRequest(*client_info);
+
+ ResetEvent(client_info->dump_requested_handle());
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
+ assert(context);
+ ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+ CrashGenerationServer* crash_server = client_info->crash_server();
+ assert(crash_server);
+
+ InterlockedIncrement(&crash_server->cleanup_item_count_);
+
+ if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {
+ InterlockedDecrement(&crash_server->cleanup_item_count_);
+ }
+}
+
+// static
+DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {
+ assert(context);
+ ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+ CrashGenerationServer* crash_server = client_info->crash_server();
+ assert(crash_server);
+
+ if (crash_server->exit_callback_) {
+ crash_server->exit_callback_(crash_server->exit_context_, client_info);
+ }
+
+ crash_server->DoCleanup(client_info);
+
+ InterlockedDecrement(&crash_server->cleanup_item_count_);
+ return 0;
+}
+
+void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
+ assert(client_info);
+
+ // Start a new scope to release lock automatically.
+ {
+ AutoCriticalSection lock(&clients_sync_);
+ clients_.remove(client_info);
+ }
+
+ delete client_info;
+}
+
+void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
+ // Generate the dump only if it's explicitly requested by the
+ // server application; otherwise the server might want to generate
+ // dump in the callback.
+ if (generate_dumps_) {
+ if (!GenerateDump(client_info)) {
+ return;
+ }
+ }
+
+ if (dump_callback_) {
+ dump_callback_(dump_context_, &client_info);
+ }
+
+ SetEvent(client_info.dump_generated_handle());
+}
+
+bool CrashGenerationServer::GenerateDump(const ClientInfo& client) {
+ assert(client.pid() != 0);
+ assert(client.process_handle());
+
+ // We have to get the address of EXCEPTION_INFORMATION from
+ // the client process address space.
+ EXCEPTION_POINTERS* client_ex_info = NULL;
+ if (!client.GetClientExceptionInfo(&client_ex_info)) {
+ return false;
+ }
+
+ DWORD client_thread_id = 0;
+ if (!client.GetClientThreadId(&client_thread_id)) {
+ return false;
+ }
+
+ return dump_generator_->WriteMinidump(client.process_handle(),
+ client.pid(),
+ client_thread_id,
+ GetCurrentThreadId(),
+ client_ex_info,
+ client.assert_info(),
+ client.dump_type(),
+ true);
+}
+
+} // namespace google_breakpad
diff --git a/src/client/windows/crash_generation/crash_generation_server.h b/src/client/windows/crash_generation/crash_generation_server.h
index 57fa2ec3..f2bfc8e6 100644
--- a/src/client/windows/crash_generation/crash_generation_server.h
+++ b/src/client/windows/crash_generation/crash_generation_server.h
@@ -1,260 +1,260 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
-#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
-
-#include <list>
-#include <string>
-#include "client/windows/common/ipc_protocol.h"
-#include "client/windows/crash_generation/client_info.h"
-#include "client/windows/crash_generation/minidump_generator.h"
-#include "processor/scoped_ptr.h"
-
-namespace google_breakpad {
-
-// Abstraction for server side implementation of out-of-process crash
-// generation protocol for Windows platform only. It generates Windows
-// minidump files for client processes that request dump generation. When
-// the server is requested to start listening for clients (by calling the
-// Start method), it creates a named pipe and waits for the clients to
-// register. In response, it hands them event handles that the client can
-// signal to request dump generation. When the clients request dump
-// generation in this way, the server generates Windows minidump files.
-class CrashGenerationServer {
- public:
- typedef void (*OnClientConnectedCallback)(void* context,
- const ClientInfo* client_info);
-
- typedef void (*OnClientDumpRequestCallback)(void* context,
- const ClientInfo* client_info);
-
- typedef void (*OnClientExitedCallback)(void* context,
- const ClientInfo* client_info);
-
- // Creates an instance with the given parameters.
- //
- // Parameter pipe_name: Name of the Windows Named pipe
- // Parameter connect_callback: Callback for a new client connection.
- // Parameter connect_context: Context for client connection callback.
- // Parameter crash_callback: Callback for a client crash dump request.
- // Parameter crash_context: Context for client crash dump request callback.
- // Parameter exit_callback: Callback for client process exit.
- // Parameter exit_context: Context for client exit callback.
- // Parameter generate_dumps: Whether to automatically generate dumps.
- // Client code of this class might want to generate dumps explicitly in the
- // crash dump request callback. In that case, false can be passed for this
- // parameter.
- // Parameter dump_path: Path for generating dumps; required only if true is
- // passed for generateDumps parameter; NULL can be passed otherwise.
- CrashGenerationServer(const std::wstring& pipe_name,
- OnClientConnectedCallback connect_callback,
- void* connect_context,
- OnClientDumpRequestCallback dump_callback,
- void* dump_context,
- OnClientExitedCallback exit_callback,
- void* exit_context,
- bool generate_dumps,
- const std::wstring* dump_path);
-
- ~CrashGenerationServer();
-
- // Performs initialization steps needed to start listening to clients.
- //
- // Returns true if initialization is successful; false otherwise.
- bool Start();
-
- private:
- // Various states the client can be in during the handshake with
- // the server.
- enum IPCServerState {
- // Server is in error state and it cannot serve any clients.
- IPC_SERVER_STATE_ERROR,
-
- // Server starts in this state.
- IPC_SERVER_STATE_INITIAL,
-
- // Server has issued an async connect to the pipe and it is waiting
- // for the connection to be established.
- IPC_SERVER_STATE_CONNECTING,
-
- // Server is connected successfully.
- IPC_SERVER_STATE_CONNECTED,
-
- // Server has issued an async read from the pipe and it is waiting for
- // the read to finish.
- IPC_SERVER_STATE_READING,
-
- // Server is done reading from the pipe.
- IPC_SERVER_STATE_READ_DONE,
-
- // Server has issued an async write to the pipe and it is waiting for
- // the write to finish.
- IPC_SERVER_STATE_WRITING,
-
- // Server is done writing to the pipe.
- IPC_SERVER_STATE_WRITE_DONE,
-
- // Server has issued an async read from the pipe for an ack and it
- // is waiting for the read to finish.
- IPC_SERVER_STATE_READING_ACK,
-
- // Server is done writing to the pipe and it is now ready to disconnect
- // and reconnect.
- IPC_SERVER_STATE_DISCONNECTING
- };
-
- //
- // Helper methods to handle various server IPC states.
- //
- void HandleErrorState();
- void HandleInitialState();
- void HandleConnectingState();
- void HandleConnectedState();
- void HandleReadingState();
- void HandleReadDoneState();
- void HandleWritingState();
- void HandleWriteDoneState();
- void HandleReadingAckState();
- void HandleDisconnectingState();
-
- // Prepares reply for a client from the given parameters.
- bool PrepareReply(const ClientInfo& client_info,
- ProtocolMessage* reply) const;
-
- // Duplicates various handles in the ClientInfo object for the client
- // process and stores them in the given ProtocolMessage instance. If
- // creating any handle fails, ProtocolMessage will contain the handles
- // already created successfully, which should be closed by the caller.
- bool CreateClientHandles(const ClientInfo& client_info,
- ProtocolMessage* reply) const;
-
- // Response to the given client. Return true if all steps of
- // responding to the client succeed, false otherwise.
- bool RespondToClient(ClientInfo* client_info);
-
- // Handles a connection request from the client.
- void HandleConnectionRequest();
-
- // Handles a dump request from the client.
- void HandleDumpRequest(const ClientInfo& client_info);
-
- // Callback for pipe connected event.
- static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
-
- // Callback for a dump request.
- static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
-
- // Callback for client process exit event.
- static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
-
- // Releases resources for a client.
- static DWORD WINAPI CleanupClient(void* context);
-
- // Cleans up for the given client.
- void DoCleanup(ClientInfo* client_info);
-
- // Adds the given client to the list of registered clients.
- bool AddClient(ClientInfo* client_info);
-
- // Generates dump for the given client.
- bool GenerateDump(const ClientInfo& client);
-
- // Sync object for thread-safe access to the shared list of clients.
- CRITICAL_SECTION clients_sync_;
-
- // List of clients.
- std::list<ClientInfo*> clients_;
-
- // Pipe name.
- std::wstring pipe_name_;
-
- // Handle to the pipe used for handshake with clients.
- HANDLE pipe_;
-
- // Pipe wait handle.
- HANDLE pipe_wait_handle_;
-
- // Handle to server-alive mutex.
- HANDLE server_alive_handle_;
-
- // Callback for a successful client connection.
- OnClientConnectedCallback connect_callback_;
-
- // Context for client connected callback.
- void* connect_context_;
-
- // Callback for a client dump request.
- OnClientDumpRequestCallback dump_callback_;
-
- // Context for client dump request callback.
- void* dump_context_;
-
- // Callback for client process exit.
- OnClientExitedCallback exit_callback_;
-
- // Context for client process exit callback.
- void* exit_context_;
-
- // Whether to generate dumps.
- bool generate_dumps_;
-
- // Instance of a mini dump generator.
- scoped_ptr<MinidumpGenerator> dump_generator_;
-
- // State of the server in performing the IPC with the client.
- // Note that since we restrict the pipe to one instance, we
- // only need to keep one state of the server. Otherwise, server
- // would have one state per client it is talking to.
- IPCServerState server_state_;
-
- // Whether the server is shutting down.
- volatile bool shutting_down_;
-
- // Overlapped instance for async I/O on the pipe.
- OVERLAPPED overlapped_;
-
- // Message object used in IPC with the client.
- ProtocolMessage msg_;
-
- // Client Info for the client that's connecting to the server.
- ClientInfo* client_info_;
-
- // Count of clean-up work items that are currently running or are
- // already queued to run.
- volatile LONG cleanup_item_count_;
-
- // Disable copy ctor and operator=.
- CrashGenerationServer(const CrashGenerationServer& crash_server);
- CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+
+#include <list>
+#include <string>
+#include "client/windows/common/ipc_protocol.h"
+#include "client/windows/crash_generation/client_info.h"
+#include "client/windows/crash_generation/minidump_generator.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+// Abstraction for server side implementation of out-of-process crash
+// generation protocol for Windows platform only. It generates Windows
+// minidump files for client processes that request dump generation. When
+// the server is requested to start listening for clients (by calling the
+// Start method), it creates a named pipe and waits for the clients to
+// register. In response, it hands them event handles that the client can
+// signal to request dump generation. When the clients request dump
+// generation in this way, the server generates Windows minidump files.
+class CrashGenerationServer {
+ public:
+ typedef void (*OnClientConnectedCallback)(void* context,
+ const ClientInfo* client_info);
+
+ typedef void (*OnClientDumpRequestCallback)(void* context,
+ const ClientInfo* client_info);
+
+ typedef void (*OnClientExitedCallback)(void* context,
+ const ClientInfo* client_info);
+
+ // Creates an instance with the given parameters.
+ //
+ // Parameter pipe_name: Name of the Windows Named pipe
+ // Parameter connect_callback: Callback for a new client connection.
+ // Parameter connect_context: Context for client connection callback.
+ // Parameter crash_callback: Callback for a client crash dump request.
+ // Parameter crash_context: Context for client crash dump request callback.
+ // Parameter exit_callback: Callback for client process exit.
+ // Parameter exit_context: Context for client exit callback.
+ // Parameter generate_dumps: Whether to automatically generate dumps.
+ // Client code of this class might want to generate dumps explicitly in the
+ // crash dump request callback. In that case, false can be passed for this
+ // parameter.
+ // Parameter dump_path: Path for generating dumps; required only if true is
+ // passed for generateDumps parameter; NULL can be passed otherwise.
+ CrashGenerationServer(const std::wstring& pipe_name,
+ OnClientConnectedCallback connect_callback,
+ void* connect_context,
+ OnClientDumpRequestCallback dump_callback,
+ void* dump_context,
+ OnClientExitedCallback exit_callback,
+ void* exit_context,
+ bool generate_dumps,
+ const std::wstring* dump_path);
+
+ ~CrashGenerationServer();
+
+ // Performs initialization steps needed to start listening to clients.
+ //
+ // Returns true if initialization is successful; false otherwise.
+ bool Start();
+
+ private:
+ // Various states the client can be in during the handshake with
+ // the server.
+ enum IPCServerState {
+ // Server is in error state and it cannot serve any clients.
+ IPC_SERVER_STATE_ERROR,
+
+ // Server starts in this state.
+ IPC_SERVER_STATE_INITIAL,
+
+ // Server has issued an async connect to the pipe and it is waiting
+ // for the connection to be established.
+ IPC_SERVER_STATE_CONNECTING,
+
+ // Server is connected successfully.
+ IPC_SERVER_STATE_CONNECTED,
+
+ // Server has issued an async read from the pipe and it is waiting for
+ // the read to finish.
+ IPC_SERVER_STATE_READING,
+
+ // Server is done reading from the pipe.
+ IPC_SERVER_STATE_READ_DONE,
+
+ // Server has issued an async write to the pipe and it is waiting for
+ // the write to finish.
+ IPC_SERVER_STATE_WRITING,
+
+ // Server is done writing to the pipe.
+ IPC_SERVER_STATE_WRITE_DONE,
+
+ // Server has issued an async read from the pipe for an ack and it
+ // is waiting for the read to finish.
+ IPC_SERVER_STATE_READING_ACK,
+
+ // Server is done writing to the pipe and it is now ready to disconnect
+ // and reconnect.
+ IPC_SERVER_STATE_DISCONNECTING
+ };
+
+ //
+ // Helper methods to handle various server IPC states.
+ //
+ void HandleErrorState();
+ void HandleInitialState();
+ void HandleConnectingState();
+ void HandleConnectedState();
+ void HandleReadingState();
+ void HandleReadDoneState();
+ void HandleWritingState();
+ void HandleWriteDoneState();
+ void HandleReadingAckState();
+ void HandleDisconnectingState();
+
+ // Prepares reply for a client from the given parameters.
+ bool PrepareReply(const ClientInfo& client_info,
+ ProtocolMessage* reply) const;
+
+ // Duplicates various handles in the ClientInfo object for the client
+ // process and stores them in the given ProtocolMessage instance. If
+ // creating any handle fails, ProtocolMessage will contain the handles
+ // already created successfully, which should be closed by the caller.
+ bool CreateClientHandles(const ClientInfo& client_info,
+ ProtocolMessage* reply) const;
+
+ // Response to the given client. Return true if all steps of
+ // responding to the client succeed, false otherwise.
+ bool RespondToClient(ClientInfo* client_info);
+
+ // Handles a connection request from the client.
+ void HandleConnectionRequest();
+
+ // Handles a dump request from the client.
+ void HandleDumpRequest(const ClientInfo& client_info);
+
+ // Callback for pipe connected event.
+ static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
+
+ // Callback for a dump request.
+ static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
+
+ // Callback for client process exit event.
+ static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
+
+ // Releases resources for a client.
+ static DWORD WINAPI CleanupClient(void* context);
+
+ // Cleans up for the given client.
+ void DoCleanup(ClientInfo* client_info);
+
+ // Adds the given client to the list of registered clients.
+ bool AddClient(ClientInfo* client_info);
+
+ // Generates dump for the given client.
+ bool GenerateDump(const ClientInfo& client);
+
+ // Sync object for thread-safe access to the shared list of clients.
+ CRITICAL_SECTION clients_sync_;
+
+ // List of clients.
+ std::list<ClientInfo*> clients_;
+
+ // Pipe name.
+ std::wstring pipe_name_;
+
+ // Handle to the pipe used for handshake with clients.
+ HANDLE pipe_;
+
+ // Pipe wait handle.
+ HANDLE pipe_wait_handle_;
+
+ // Handle to server-alive mutex.
+ HANDLE server_alive_handle_;
+
+ // Callback for a successful client connection.
+ OnClientConnectedCallback connect_callback_;
+
+ // Context for client connected callback.
+ void* connect_context_;
+
+ // Callback for a client dump request.
+ OnClientDumpRequestCallback dump_callback_;
+
+ // Context for client dump request callback.
+ void* dump_context_;
+
+ // Callback for client process exit.
+ OnClientExitedCallback exit_callback_;
+
+ // Context for client process exit callback.
+ void* exit_context_;
+
+ // Whether to generate dumps.
+ bool generate_dumps_;
+
+ // Instance of a mini dump generator.
+ scoped_ptr<MinidumpGenerator> dump_generator_;
+
+ // State of the server in performing the IPC with the client.
+ // Note that since we restrict the pipe to one instance, we
+ // only need to keep one state of the server. Otherwise, server
+ // would have one state per client it is talking to.
+ IPCServerState server_state_;
+
+ // Whether the server is shutting down.
+ volatile bool shutting_down_;
+
+ // Overlapped instance for async I/O on the pipe.
+ OVERLAPPED overlapped_;
+
+ // Message object used in IPC with the client.
+ ProtocolMessage msg_;
+
+ // Client Info for the client that's connecting to the server.
+ ClientInfo* client_info_;
+
+ // Count of clean-up work items that are currently running or are
+ // already queued to run.
+ volatile LONG cleanup_item_count_;
+
+ // Disable copy ctor and operator=.
+ CrashGenerationServer(const CrashGenerationServer& crash_server);
+ CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc
index 6081e4b2..7d3e2f6b 100644
--- a/src/client/windows/crash_generation/minidump_generator.cc
+++ b/src/client/windows/crash_generation/minidump_generator.cc
@@ -1,228 +1,228 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "client/windows/crash_generation/minidump_generator.h"
-#include <cassert>
-#include "client/windows/common/auto_critical_section.h"
-#include "common/windows/guid_string.h"
-
-using std::wstring;
-
-namespace google_breakpad {
-
-MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
- : dbghelp_module_(NULL),
- rpcrt4_module_(NULL),
- dump_path_(dump_path),
- write_dump_(NULL),
- create_uuid_(NULL) {
- InitializeCriticalSection(&module_load_sync_);
- InitializeCriticalSection(&get_proc_address_sync_);
-}
-
-MinidumpGenerator::~MinidumpGenerator() {
- if (dbghelp_module_) {
- FreeLibrary(dbghelp_module_);
- }
-
- if (rpcrt4_module_) {
- FreeLibrary(rpcrt4_module_);
- }
-
- DeleteCriticalSection(&get_proc_address_sync_);
- DeleteCriticalSection(&module_load_sync_);
-}
-
-bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
- DWORD process_id,
- DWORD thread_id,
- DWORD requesting_thread_id,
- EXCEPTION_POINTERS* exception_pointers,
- MDRawAssertionInfo* assert_info,
- MINIDUMP_TYPE dump_type,
- bool is_client_pointers) {
- MiniDumpWriteDumpType write_dump = GetWriteDump();
- if (!write_dump) {
- return false;
- }
-
- wstring dump_file_path;
- if (!GenerateDumpFilePath(&dump_file_path)) {
- return false;
- }
-
- HANDLE dump_file = CreateFile(dump_file_path.c_str(),
- GENERIC_WRITE,
- 0,
- NULL,
- CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- if (dump_file == INVALID_HANDLE_VALUE) {
- return false;
- }
-
- MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
- MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
-
- // Setup the exception information object only if it's a dump
- // due to an exception.
- if (exception_pointers) {
- dump_exception_pointers = &dump_exception_info;
- dump_exception_info.ThreadId = thread_id;
- dump_exception_info.ExceptionPointers = exception_pointers;
- dump_exception_info.ClientPointers = is_client_pointers;
- }
-
- // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
- // information about the exception handler to the Breakpad processor.
- // The information will help the processor determine which threads are
- // relevant. The Breakpad processor does not require this information but
- // can function better with Breakpad-generated dumps when it is present.
- // The native debugger is not harmed by the presence of this information.
- MDRawBreakpadInfo breakpad_info;
- breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
- MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
- breakpad_info.dump_thread_id = thread_id;
- breakpad_info.requesting_thread_id = requesting_thread_id;
-
- // Leave room in user_stream_array for a possible assertion info stream.
- MINIDUMP_USER_STREAM user_stream_array[2];
- user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
- user_stream_array[0].BufferSize = sizeof(breakpad_info);
- user_stream_array[0].Buffer = &breakpad_info;
-
- MINIDUMP_USER_STREAM_INFORMATION user_streams;
- user_streams.UserStreamCount = 1;
- user_streams.UserStreamArray = user_stream_array;
-
- MDRawAssertionInfo* actual_assert_info = assert_info;
- MDRawAssertionInfo client_assert_info = {0};
-
- if (assert_info) {
- // If the assertion info object lives in the client process,
- // read the memory of the client process.
- if (is_client_pointers) {
- SIZE_T bytes_read = 0;
- if (!ReadProcessMemory(process_handle,
- assert_info,
- &client_assert_info,
- sizeof(client_assert_info),
- &bytes_read)) {
- CloseHandle(dump_file);
- return false;
- }
-
- if (bytes_read != sizeof(client_assert_info)) {
- CloseHandle(dump_file);
- return false;
- }
-
- actual_assert_info = &client_assert_info;
- }
-
- user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
- user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
- user_stream_array[1].Buffer = actual_assert_info;
- ++user_streams.UserStreamCount;
- }
-
- bool result = write_dump(process_handle,
- process_id,
- dump_file,
- dump_type,
- exception_pointers ? &dump_exception_info : NULL,
- &user_streams,
- NULL) != FALSE;
-
- CloseHandle(dump_file);
- return result;
-}
-
-HMODULE MinidumpGenerator::GetDbghelpModule() {
- AutoCriticalSection lock(&module_load_sync_);
- if (!dbghelp_module_) {
- dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
- }
-
- return dbghelp_module_;
-}
-
-MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
- AutoCriticalSection lock(&get_proc_address_sync_);
- if (!write_dump_) {
- HMODULE module = GetDbghelpModule();
- if (module) {
- FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
- write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
- }
- }
-
- return write_dump_;
-}
-
-HMODULE MinidumpGenerator::GetRpcrt4Module() {
- AutoCriticalSection lock(&module_load_sync_);
- if (!rpcrt4_module_) {
- rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
- }
-
- return rpcrt4_module_;
-}
-
-MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
- AutoCriticalSection lock(&module_load_sync_);
- if (!create_uuid_) {
- HMODULE module = GetRpcrt4Module();
- if (module) {
- FARPROC proc = GetProcAddress(module, "UuidCreate");
- create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
- }
- }
-
- return create_uuid_;
-}
-
-bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
- UUID id = {0};
-
- UuidCreateType create_uuid = GetCreateUuid();
- if(!create_uuid) {
- return false;
- }
-
- create_uuid(&id);
- wstring id_str = GUIDString::GUIDToWString(&id);
-
- *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
- return true;
-}
-
-} // namespace google_breakpad
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/minidump_generator.h"
+#include <cassert>
+#include "client/windows/common/auto_critical_section.h"
+#include "common/windows/guid_string.h"
+
+using std::wstring;
+
+namespace google_breakpad {
+
+MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
+ : dbghelp_module_(NULL),
+ rpcrt4_module_(NULL),
+ dump_path_(dump_path),
+ write_dump_(NULL),
+ create_uuid_(NULL) {
+ InitializeCriticalSection(&module_load_sync_);
+ InitializeCriticalSection(&get_proc_address_sync_);
+}
+
+MinidumpGenerator::~MinidumpGenerator() {
+ if (dbghelp_module_) {
+ FreeLibrary(dbghelp_module_);
+ }
+
+ if (rpcrt4_module_) {
+ FreeLibrary(rpcrt4_module_);
+ }
+
+ DeleteCriticalSection(&get_proc_address_sync_);
+ DeleteCriticalSection(&module_load_sync_);
+}
+
+bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
+ DWORD process_id,
+ DWORD thread_id,
+ DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exception_pointers,
+ MDRawAssertionInfo* assert_info,
+ MINIDUMP_TYPE dump_type,
+ bool is_client_pointers) {
+ MiniDumpWriteDumpType write_dump = GetWriteDump();
+ if (!write_dump) {
+ return false;
+ }
+
+ wstring dump_file_path;
+ if (!GenerateDumpFilePath(&dump_file_path)) {
+ return false;
+ }
+
+ HANDLE dump_file = CreateFile(dump_file_path.c_str(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (dump_file == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
+ MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
+
+ // Setup the exception information object only if it's a dump
+ // due to an exception.
+ if (exception_pointers) {
+ dump_exception_pointers = &dump_exception_info;
+ dump_exception_info.ThreadId = thread_id;
+ dump_exception_info.ExceptionPointers = exception_pointers;
+ dump_exception_info.ClientPointers = is_client_pointers;
+ }
+
+ // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
+ // information about the exception handler to the Breakpad processor.
+ // The information will help the processor determine which threads are
+ // relevant. The Breakpad processor does not require this information but
+ // can function better with Breakpad-generated dumps when it is present.
+ // The native debugger is not harmed by the presence of this information.
+ MDRawBreakpadInfo breakpad_info;
+ breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+ MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+ breakpad_info.dump_thread_id = thread_id;
+ breakpad_info.requesting_thread_id = requesting_thread_id;
+
+ // Leave room in user_stream_array for a possible assertion info stream.
+ MINIDUMP_USER_STREAM user_stream_array[2];
+ user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
+ user_stream_array[0].BufferSize = sizeof(breakpad_info);
+ user_stream_array[0].Buffer = &breakpad_info;
+
+ MINIDUMP_USER_STREAM_INFORMATION user_streams;
+ user_streams.UserStreamCount = 1;
+ user_streams.UserStreamArray = user_stream_array;
+
+ MDRawAssertionInfo* actual_assert_info = assert_info;
+ MDRawAssertionInfo client_assert_info = {0};
+
+ if (assert_info) {
+ // If the assertion info object lives in the client process,
+ // read the memory of the client process.
+ if (is_client_pointers) {
+ SIZE_T bytes_read = 0;
+ if (!ReadProcessMemory(process_handle,
+ assert_info,
+ &client_assert_info,
+ sizeof(client_assert_info),
+ &bytes_read)) {
+ CloseHandle(dump_file);
+ return false;
+ }
+
+ if (bytes_read != sizeof(client_assert_info)) {
+ CloseHandle(dump_file);
+ return false;
+ }
+
+ actual_assert_info = &client_assert_info;
+ }
+
+ user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
+ user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
+ user_stream_array[1].Buffer = actual_assert_info;
+ ++user_streams.UserStreamCount;
+ }
+
+ bool result = write_dump(process_handle,
+ process_id,
+ dump_file,
+ dump_type,
+ exception_pointers ? &dump_exception_info : NULL,
+ &user_streams,
+ NULL) != FALSE;
+
+ CloseHandle(dump_file);
+ return result;
+}
+
+HMODULE MinidumpGenerator::GetDbghelpModule() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!dbghelp_module_) {
+ dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
+ }
+
+ return dbghelp_module_;
+}
+
+MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
+ AutoCriticalSection lock(&get_proc_address_sync_);
+ if (!write_dump_) {
+ HMODULE module = GetDbghelpModule();
+ if (module) {
+ FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
+ write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
+ }
+ }
+
+ return write_dump_;
+}
+
+HMODULE MinidumpGenerator::GetRpcrt4Module() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!rpcrt4_module_) {
+ rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
+ }
+
+ return rpcrt4_module_;
+}
+
+MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!create_uuid_) {
+ HMODULE module = GetRpcrt4Module();
+ if (module) {
+ FARPROC proc = GetProcAddress(module, "UuidCreate");
+ create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
+ }
+ }
+
+ return create_uuid_;
+}
+
+bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
+ UUID id = {0};
+
+ UuidCreateType create_uuid = GetCreateUuid();
+ if(!create_uuid) {
+ return false;
+ }
+
+ create_uuid(&id);
+ wstring id_str = GUIDString::GUIDToWString(&id);
+
+ *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/src/client/windows/crash_generation/minidump_generator.h b/src/client/windows/crash_generation/minidump_generator.h
index b14fc67b..e343a0ab 100644
--- a/src/client/windows/crash_generation/minidump_generator.h
+++ b/src/client/windows/crash_generation/minidump_generator.h
@@ -1,118 +1,118 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
-#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
-
-#include <windows.h>
-#include <dbghelp.h>
-#include <list>
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-// Abstraction for various objects and operations needed to generate
-// minidump on Windows. This abstraction is useful to hide all the gory
-// details for minidump generation and provide a clean interface to
-// the clients to generate minidumps.
-class MinidumpGenerator {
- public:
- // Creates an instance with the given dump path.
- explicit MinidumpGenerator(const std::wstring& dump_path);
-
- ~MinidumpGenerator();
-
- // Writes the minidump with the given parameters.
- bool WriteMinidump(HANDLE process_handle,
- DWORD process_id,
- DWORD thread_id,
- DWORD requesting_thread_id,
- EXCEPTION_POINTERS* exception_pointers,
- MDRawAssertionInfo* assert_info,
- MINIDUMP_TYPE dump_type,
- bool is_client_pointers);
-
- private:
- // Function pointer type for MiniDumpWriteDump, which is looked up
- // dynamically.
- typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
- HANDLE hProcess,
- DWORD ProcessId,
- HANDLE hFile,
- MINIDUMP_TYPE DumpType,
- CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
-
- // Function pointer type for UuidCreate, which is looked up dynamically.
- typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
-
- // Loads the appropriate DLL lazily in a thread safe way.
- HMODULE GetDbghelpModule();
-
- // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
- // function lazily and in a thread-safe manner.
- MiniDumpWriteDumpType GetWriteDump();
-
- // Loads the appropriate DLL lazily in a thread safe way.
- HMODULE GetRpcrt4Module();
-
- // Loads the appropriate DLL and gets a pointer to the UuidCreate
- // function lazily and in a thread-safe manner.
- UuidCreateType GetCreateUuid();
-
- // Returns the path for the file to write dump to.
- bool GenerateDumpFilePath(std::wstring* file_path);
-
- // Handle to dynamically loaded DbgHelp.dll.
- HMODULE dbghelp_module_;
-
- // Pointer to the MiniDumpWriteDump function.
- MiniDumpWriteDumpType write_dump_;
-
- // Handle to dynamically loaded rpcrt4.dll.
- HMODULE rpcrt4_module_;
-
- // Pointer to the UuidCreate function.
- UuidCreateType create_uuid_;
-
- // Folder path to store dump files.
- std::wstring dump_path_;
-
- // Critical section to sychronize action of loading modules dynamically.
- CRITICAL_SECTION module_load_sync_;
-
- // Critical section to synchronize action of dynamically getting function
- // addresses from modules.
- CRITICAL_SECTION get_proc_address_sync_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <list>
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Abstraction for various objects and operations needed to generate
+// minidump on Windows. This abstraction is useful to hide all the gory
+// details for minidump generation and provide a clean interface to
+// the clients to generate minidumps.
+class MinidumpGenerator {
+ public:
+ // Creates an instance with the given dump path.
+ explicit MinidumpGenerator(const std::wstring& dump_path);
+
+ ~MinidumpGenerator();
+
+ // Writes the minidump with the given parameters.
+ bool WriteMinidump(HANDLE process_handle,
+ DWORD process_id,
+ DWORD thread_id,
+ DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exception_pointers,
+ MDRawAssertionInfo* assert_info,
+ MINIDUMP_TYPE dump_type,
+ bool is_client_pointers);
+
+ private:
+ // Function pointer type for MiniDumpWriteDump, which is looked up
+ // dynamically.
+ typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
+ HANDLE hProcess,
+ DWORD ProcessId,
+ HANDLE hFile,
+ MINIDUMP_TYPE DumpType,
+ CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+ // Function pointer type for UuidCreate, which is looked up dynamically.
+ typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
+
+ // Loads the appropriate DLL lazily in a thread safe way.
+ HMODULE GetDbghelpModule();
+
+ // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
+ // function lazily and in a thread-safe manner.
+ MiniDumpWriteDumpType GetWriteDump();
+
+ // Loads the appropriate DLL lazily in a thread safe way.
+ HMODULE GetRpcrt4Module();
+
+ // Loads the appropriate DLL and gets a pointer to the UuidCreate
+ // function lazily and in a thread-safe manner.
+ UuidCreateType GetCreateUuid();
+
+ // Returns the path for the file to write dump to.
+ bool GenerateDumpFilePath(std::wstring* file_path);
+
+ // Handle to dynamically loaded DbgHelp.dll.
+ HMODULE dbghelp_module_;
+
+ // Pointer to the MiniDumpWriteDump function.
+ MiniDumpWriteDumpType write_dump_;
+
+ // Handle to dynamically loaded rpcrt4.dll.
+ HMODULE rpcrt4_module_;
+
+ // Pointer to the UuidCreate function.
+ UuidCreateType create_uuid_;
+
+ // Folder path to store dump files.
+ std::wstring dump_path_;
+
+ // Critical section to sychronize action of loading modules dynamically.
+ CRITICAL_SECTION module_load_sync_;
+
+ // Critical section to synchronize action of dynamically getting function
+ // addresses from modules.
+ CRITICAL_SECTION get_proc_address_sync_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__