crashpad client for windows

Introduces CrashpadClient::SetHandler()

The code in the cc plays it fast and loose but helps ground
the intention.

BUG=crashpad:1
R=mark@chromium.org, scottmg@chromium.org

Review URL: https://codereview.chromium.org/1095273003
This commit is contained in:
Carlos Pizano 2015-04-29 18:53:47 -07:00
parent 7b7205fe52
commit dd3c20667d
3 changed files with 118 additions and 1 deletions

View File

@ -37,6 +37,7 @@
'crash_report_database_win.cc',
'crashpad_client.h',
'crashpad_client_mac.cc',
'crashpad_client_win.cc',
'crashpad_info.cc',
'crashpad_info.h',
'settings.cc',

View File

@ -49,6 +49,9 @@ class CrashpadClient {
//! send right corresponding to a receive right held by the handler process.
//! The handler process runs an exception server on this port.
//!
//! On Windows, SetHandler() is normally used instead since the handler is
//! started by other means.
//!
//! \param[in] handler The path to a Crashpad handler executable.
//! \param[in] database The path to a Crashpad database. The handler will be
//! started with this path as its `--database` argument.
@ -69,9 +72,27 @@ class CrashpadClient {
const std::map<std::string, std::string>& annotations,
const std::vector<std::string>& arguments);
#if defined(OS_WIN) || DOXYGEN
//! \brief Sets the IPC port of a presumably-running Crashpad handler process
//! which was started with StartHandler() or by other compatible means
//! and does an IPC message exchange to register this process with the
//! handler. However, just like StartHandler(), crashes are not serviced
//! until UseHandler() is called.
//!
//! The IPC port name (somehow) encodes enough information so that
//! registration is done with a crash handler using the appropriate database
//! and upload server.
//!
//! \param[in] ipc_port The full name of the crash handler IPC port.
//!
//! \return `true` on success and `false` on failure.
bool SetHandler(const std::string& ipc_port);
#endif
//! \brief Configures the process to direct its crashes to a Crashpad handler.
//!
//! The Crashpad handler must previously have been started by StartHandler().
//! The Crashpad handler must previously have been started by StartHandler()
//! or configured by SetHandler().
//!
//! On Mac OS X, this method sets the tasks exception port for `EXC_CRASH`,
//! `EXC_RESOURCE`, and `EXC_GUARD` exceptions to the Mach send right obtained
@ -85,6 +106,10 @@ class CrashpadClient {
//! have inherited it as their exception handler even after the process that
//! called StartHandler() exits.
//!
//! On Windows, this method sets the unhandled exception handler to a local
//! function that when reached will "signal and wait" for the crash handler
//! process to create the dump.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool UseHandler();

View File

@ -0,0 +1,91 @@
// Copyright 2015 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/crashpad_client.h"
#include <windows.h>
#include "base/logging.h"
namespace {
// Time to wait for the handler to create a dump. This is tricky to figure out.
const DWORD kMillisecondsUntilTerminate = 5000;
// This is the exit code that the process will return to the system once the
// crash has been handled by Crashpad. We don't want to clash with the
// application-defined exit codes but we don't know them so we use one that is
// unlikely to be used.
const UINT kCrashExitCode = 0xffff7001;
// These two handles to events are leaked.
HANDLE g_signal_exception = nullptr;
HANDLE g_wait_termination = nullptr;
LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
// TODO (cpu): Here write |exception_pointers| to g_crashpad_info.
DWORD rv = SignalObjectAndWait(g_signal_exception,
g_wait_termination,
kMillisecondsUntilTerminate,
FALSE);
if (rv != WAIT_OBJECT_0) {
// Something went wrong. It is likely that a dump has not been created.
if (rv == WAIT_TIMEOUT) {
LOG(WARNING) << "SignalObjectAndWait timed out";
} else {
PLOG(WARNING) << "SignalObjectAndWait error";
}
}
// We don't want to generate more exceptions, so we take the fast route.
TerminateProcess(GetCurrentProcess(), kCrashExitCode);
return 0L;
}
} // namespace
namespace crashpad {
CrashpadClient::CrashpadClient() {
}
CrashpadClient::~CrashpadClient() {
}
bool CrashpadClient::StartHandler(
const base::FilePath& handler,
const base::FilePath& database,
const std::string& url,
const std::map<std::string, std::string>& annotations,
const std::vector<std::string>& arguments) {
// TODO(cpu): Provide a reference implementation.
return false;
}
bool SetHandler(const std::string& ipc_port) {
// TODO (cpu): Contact the handler and obtain g_signal_exception and
// g_wait_termination.
return false;
}
bool CrashpadClient::UseHandler() {
if (!g_signal_exception)
return false;
if (!g_wait_termination)
return false;
// In theory we could store the previous handler but it is not clear what
// use we have for it.
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
return true;
}
} // namespace crashpad