mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-17 16:43:53 +00:00
linux: Implement StartHandler()
This CL adds a RequestCrashDumpHandler to request a crash dump over a socket. Common functionality with LaunchAtCrashHandler is factored out into a SignalHandler base class. Bug: crashpad:284 Change-Id: I86293ef599a0dd6eea63c096a5c931c620c05ecc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1568985 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
e23286dc37
commit
607c80e0b8
@ -78,6 +78,10 @@ class CrashpadClient {
|
|||||||
//! On Fuchsia, this method binds to the exception port of the current default
|
//! On Fuchsia, this method binds to the exception port of the current default
|
||||||
//! job, and starts a Crashpad handler to monitor that port.
|
//! job, and starts a Crashpad handler to monitor that port.
|
||||||
//!
|
//!
|
||||||
|
//! On Linux, this method starts a Crashpad handler, connected to this process
|
||||||
|
//! via an `AF_UNIX` socket pair and installs signal handlers to request crash
|
||||||
|
//! dumps on the client's socket end.
|
||||||
|
//!
|
||||||
//! \param[in] handler The path to a Crashpad handler executable.
|
//! \param[in] handler The path to a Crashpad handler executable.
|
||||||
//! \param[in] database The path to a Crashpad database. The handler will be
|
//! \param[in] database The path to a Crashpad database. The handler will be
|
||||||
//! started with this path as its `--database` argument.
|
//! started with this path as its `--database` argument.
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "util/linux/exception_information.h"
|
#include "util/linux/exception_information.h"
|
||||||
#include "util/linux/scoped_pr_set_dumpable.h"
|
#include "util/linux/scoped_pr_set_dumpable.h"
|
||||||
#include "util/linux/scoped_pr_set_ptracer.h"
|
#include "util/linux/scoped_pr_set_ptracer.h"
|
||||||
|
#include "util/linux/socket.h"
|
||||||
#include "util/misc/from_pointer_cast.h"
|
#include "util/misc/from_pointer_cast.h"
|
||||||
#include "util/posix/double_fork_and_exec.h"
|
#include "util/posix/double_fork_and_exec.h"
|
||||||
#include "util/posix/signals.h"
|
#include "util/posix/signals.h"
|
||||||
@ -43,7 +44,7 @@ std::string FormatArgumentInt(const std::string& name, int value) {
|
|||||||
return base::StringPrintf("--%s=%d", name.c_str(), value);
|
return base::StringPrintf("--%s=%d", name.c_str(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatArgumentAddress(const std::string& name, void* addr) {
|
std::string FormatArgumentAddress(const std::string& name, const void* addr) {
|
||||||
return base::StringPrintf("--%s=%p", name.c_str(), addr);
|
return base::StringPrintf("--%s=%p", name.c_str(), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,8 +111,90 @@ std::vector<std::string> BuildArgsToLaunchWithLinker(
|
|||||||
|
|
||||||
#endif // OS_ANDROID
|
#endif // OS_ANDROID
|
||||||
|
|
||||||
|
// A base class for Crashpad signal handler implementations.
|
||||||
|
class SignalHandler {
|
||||||
|
public:
|
||||||
|
// Returns the currently installed signal hander. May be `nullptr` if no
|
||||||
|
// handler has been installed.
|
||||||
|
static SignalHandler* Get() { return handler_; }
|
||||||
|
|
||||||
|
// Disables any installed Crashpad signal handler for the calling thread. If a
|
||||||
|
// crash signal is received, any previously installed (non-Crashpad) signal
|
||||||
|
// handler will be restored and the signal reraised.
|
||||||
|
static void DisableForThread() { disabled_for_thread_ = true; }
|
||||||
|
|
||||||
|
void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) {
|
||||||
|
first_chance_handler_ = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The base implementation for all signal handlers, suitable for calling
|
||||||
|
// directly to simulate signal delivery.
|
||||||
|
bool HandleCrash(int signo, siginfo_t* siginfo, void* context) {
|
||||||
|
if (disabled_for_thread_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_chance_handler_ &&
|
||||||
|
first_chance_handler_(
|
||||||
|
signo, siginfo, static_cast<ucontext_t*>(context))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_information_.siginfo_address =
|
||||||
|
FromPointerCast<decltype(exception_information_.siginfo_address)>(
|
||||||
|
siginfo);
|
||||||
|
exception_information_.context_address =
|
||||||
|
FromPointerCast<decltype(exception_information_.context_address)>(
|
||||||
|
context);
|
||||||
|
exception_information_.thread_id = sys_gettid();
|
||||||
|
|
||||||
|
HandleCrashImpl();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SignalHandler() = default;
|
||||||
|
|
||||||
|
bool Install() {
|
||||||
|
DCHECK(!handler_);
|
||||||
|
handler_ = this;
|
||||||
|
return Signals::InstallCrashHandlers(
|
||||||
|
HandleOrReraiseSignal, 0, &old_actions_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExceptionInformation& GetExceptionInfo() {
|
||||||
|
return exception_information_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void HandleCrashImpl() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The signal handler installed at OS-level.
|
||||||
|
static void HandleOrReraiseSignal(int signo,
|
||||||
|
siginfo_t* siginfo,
|
||||||
|
void* context) {
|
||||||
|
if (handler_->HandleCrash(signo, siginfo, context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Signals::RestoreHandlerAndReraiseSignalOnReturn(
|
||||||
|
siginfo, handler_->old_actions_.ActionForSignal(signo));
|
||||||
|
}
|
||||||
|
|
||||||
|
Signals::OldActions old_actions_ = {};
|
||||||
|
ExceptionInformation exception_information_ = {};
|
||||||
|
CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr;
|
||||||
|
|
||||||
|
static SignalHandler* handler_;
|
||||||
|
|
||||||
|
static thread_local bool disabled_for_thread_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(SignalHandler);
|
||||||
|
};
|
||||||
|
SignalHandler* SignalHandler::handler_ = nullptr;
|
||||||
|
thread_local bool SignalHandler::disabled_for_thread_ = false;
|
||||||
|
|
||||||
// Launches a single use handler to snapshot this process.
|
// Launches a single use handler to snapshot this process.
|
||||||
class LaunchAtCrashHandler {
|
class LaunchAtCrashHandler : public SignalHandler {
|
||||||
public:
|
public:
|
||||||
static LaunchAtCrashHandler* Get() {
|
static LaunchAtCrashHandler* Get() {
|
||||||
static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler();
|
static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler();
|
||||||
@ -129,33 +212,19 @@ class LaunchAtCrashHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception",
|
argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception",
|
||||||
&exception_information_));
|
&GetExceptionInfo()));
|
||||||
|
|
||||||
StringVectorToCStringVector(argv_strings_, &argv_);
|
StringVectorToCStringVector(argv_strings_, &argv_);
|
||||||
return Signals::InstallCrashHandlers(HandleCrash, 0, &old_actions_);
|
return Install();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) {
|
void HandleCrashImpl() override {
|
||||||
if (first_chance_handler_ &&
|
|
||||||
first_chance_handler_(
|
|
||||||
signo, siginfo, static_cast<ucontext_t*>(context))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
exception_information_.siginfo_address =
|
|
||||||
FromPointerCast<decltype(exception_information_.siginfo_address)>(
|
|
||||||
siginfo);
|
|
||||||
exception_information_.context_address =
|
|
||||||
FromPointerCast<decltype(exception_information_.context_address)>(
|
|
||||||
context);
|
|
||||||
exception_information_.thread_id = syscall(SYS_gettid);
|
|
||||||
|
|
||||||
ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false);
|
ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false);
|
||||||
ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
|
ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
if (set_envp_) {
|
if (set_envp_) {
|
||||||
@ -170,52 +239,72 @@ class LaunchAtCrashHandler {
|
|||||||
|
|
||||||
int status;
|
int status;
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleCrashFatal(int signo, siginfo_t* siginfo, void* context) {
|
|
||||||
if (enabled_ && HandleCrashNonFatal(signo, siginfo, context)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Signals::RestoreHandlerAndReraiseSignalOnReturn(
|
|
||||||
siginfo, old_actions_.ActionForSignal(signo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) {
|
|
||||||
first_chance_handler_ = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Disable() { enabled_ = false; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LaunchAtCrashHandler() = default;
|
LaunchAtCrashHandler() = default;
|
||||||
|
|
||||||
~LaunchAtCrashHandler() = delete;
|
~LaunchAtCrashHandler() = delete;
|
||||||
|
|
||||||
static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
|
|
||||||
auto state = Get();
|
|
||||||
state->HandleCrashFatal(signo, siginfo, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
Signals::OldActions old_actions_ = {};
|
|
||||||
std::vector<std::string> argv_strings_;
|
std::vector<std::string> argv_strings_;
|
||||||
std::vector<const char*> argv_;
|
std::vector<const char*> argv_;
|
||||||
std::vector<std::string> envp_strings_;
|
std::vector<std::string> envp_strings_;
|
||||||
std::vector<const char*> envp_;
|
std::vector<const char*> envp_;
|
||||||
ExceptionInformation exception_information_;
|
|
||||||
CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr;
|
|
||||||
bool set_envp_ = false;
|
bool set_envp_ = false;
|
||||||
|
|
||||||
static thread_local bool enabled_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler);
|
DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler);
|
||||||
};
|
};
|
||||||
thread_local bool LaunchAtCrashHandler::enabled_ = true;
|
|
||||||
|
|
||||||
// A pointer to the currently installed crash signal handler. This allows
|
class RequestCrashDumpHandler : public SignalHandler {
|
||||||
// the static method CrashpadClient::DumpWithoutCrashing to simulate a crash
|
public:
|
||||||
// using the currently configured crash handling strategy.
|
static RequestCrashDumpHandler* Get() {
|
||||||
static LaunchAtCrashHandler* g_crash_handler;
|
static RequestCrashDumpHandler* instance = new RequestCrashDumpHandler();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pid < 0 indicates the handler pid should be determined by communicating
|
||||||
|
// over the socket.
|
||||||
|
// pid == 0 indicates it is not necessary to set the handler as this process'
|
||||||
|
// ptracer. e.g. if the handler has CAP_SYS_PTRACE or if this process is in a
|
||||||
|
// user namespace and the handler's uid matches the uid of the process that
|
||||||
|
// created the namespace.
|
||||||
|
// pid > 0 directly indicates what the handler's pid is expected to be, so
|
||||||
|
// retrieving this information from the handler is not necessary.
|
||||||
|
bool Initialize(ScopedFileHandle sock, pid_t pid) {
|
||||||
|
ExceptionHandlerClient client(sock.get(), true);
|
||||||
|
if (pid < 0) {
|
||||||
|
ucred creds;
|
||||||
|
if (!client.GetHandlerCredentials(&creds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pid = creds.pid;
|
||||||
|
}
|
||||||
|
if (pid > 0 && client.SetPtracer(pid) != 0) {
|
||||||
|
LOG(ERROR) << "failed to set ptracer";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sock_to_handler_.reset(sock.release());
|
||||||
|
return Install();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleCrashImpl() override {
|
||||||
|
ExceptionHandlerProtocol::ClientInformation info = {};
|
||||||
|
info.exception_information_address =
|
||||||
|
FromPointerCast<VMAddress>(&GetExceptionInfo());
|
||||||
|
|
||||||
|
ExceptionHandlerClient client(sock_to_handler_.get(), true);
|
||||||
|
client.RequestCrashDump(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RequestCrashDumpHandler() = default;
|
||||||
|
|
||||||
|
~RequestCrashDumpHandler() = delete;
|
||||||
|
|
||||||
|
ScopedFileHandle sock_to_handler_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -232,11 +321,26 @@ bool CrashpadClient::StartHandler(
|
|||||||
const std::vector<std::string>& arguments,
|
const std::vector<std::string>& arguments,
|
||||||
bool restartable,
|
bool restartable,
|
||||||
bool asynchronous_start) {
|
bool asynchronous_start) {
|
||||||
// TODO(jperaza): Implement this after the Android/Linux ExceptionHandlerSever
|
DCHECK(!restartable);
|
||||||
// supports accepting new connections.
|
DCHECK(!asynchronous_start);
|
||||||
// https://crashpad.chromium.org/bug/30
|
|
||||||
NOTREACHED();
|
ScopedFileHandle client_sock, handler_sock;
|
||||||
|
if (!UnixCredentialSocket::CreateCredentialSocketpair(&client_sock,
|
||||||
|
&handler_sock)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> argv = BuildHandlerArgvStrings(
|
||||||
|
handler, database, metrics_dir, url, annotations, arguments);
|
||||||
|
|
||||||
|
argv.push_back(FormatArgumentInt("initial-client-fd", handler_sock.get()));
|
||||||
|
argv.push_back("--shared-client-connection");
|
||||||
|
if (!DoubleForkAndExec(argv, nullptr, handler_sock.get(), false, nullptr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto signal_handler = RequestCrashDumpHandler::Get();
|
||||||
|
return signal_handler->Initialize(std::move(client_sock), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_ANDROID)
|
#if defined(OS_ANDROID)
|
||||||
@ -259,12 +363,7 @@ bool CrashpadClient::StartJavaHandlerAtCrash(
|
|||||||
kInvalidFileHandle);
|
kInvalidFileHandle);
|
||||||
|
|
||||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||||
if (signal_handler->Initialize(&argv, env)) {
|
return signal_handler->Initialize(&argv, env);
|
||||||
DCHECK(!g_crash_handler);
|
|
||||||
g_crash_handler = signal_handler;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -304,12 +403,7 @@ bool CrashpadClient::StartHandlerWithLinkerAtCrash(
|
|||||||
arguments,
|
arguments,
|
||||||
kInvalidFileHandle);
|
kInvalidFileHandle);
|
||||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||||
if (signal_handler->Initialize(&argv, env)) {
|
return signal_handler->Initialize(&argv, env);
|
||||||
DCHECK(!g_crash_handler);
|
|
||||||
g_crash_handler = signal_handler;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -351,12 +445,7 @@ bool CrashpadClient::StartHandlerAtCrash(
|
|||||||
handler, database, metrics_dir, url, annotations, arguments);
|
handler, database, metrics_dir, url, annotations, arguments);
|
||||||
|
|
||||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||||
if (signal_handler->Initialize(&argv, nullptr)) {
|
return signal_handler->Initialize(&argv, nullptr);
|
||||||
DCHECK(!g_crash_handler);
|
|
||||||
g_crash_handler = signal_handler;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -378,7 +467,7 @@ bool CrashpadClient::StartHandlerForClient(
|
|||||||
|
|
||||||
// static
|
// static
|
||||||
void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) {
|
void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) {
|
||||||
if (!g_crash_handler) {
|
if (!SignalHandler::Get()) {
|
||||||
DLOG(ERROR) << "Crashpad isn't enabled";
|
DLOG(ERROR) << "Crashpad isn't enabled";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -395,21 +484,21 @@ void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) {
|
|||||||
siginfo.si_signo = Signals::kSimulatedSigno;
|
siginfo.si_signo = Signals::kSimulatedSigno;
|
||||||
siginfo.si_errno = 0;
|
siginfo.si_errno = 0;
|
||||||
siginfo.si_code = 0;
|
siginfo.si_code = 0;
|
||||||
g_crash_handler->HandleCrashNonFatal(
|
SignalHandler::Get()->HandleCrash(
|
||||||
siginfo.si_signo, &siginfo, reinterpret_cast<void*>(context));
|
siginfo.si_signo, &siginfo, reinterpret_cast<void*>(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void CrashpadClient::CrashWithoutDump(const std::string& message) {
|
void CrashpadClient::CrashWithoutDump(const std::string& message) {
|
||||||
LaunchAtCrashHandler::Disable();
|
SignalHandler::DisableForThread();
|
||||||
LOG(FATAL) << message;
|
LOG(FATAL) << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void CrashpadClient::SetFirstChanceExceptionHandler(
|
void CrashpadClient::SetFirstChanceExceptionHandler(
|
||||||
FirstChanceHandler handler) {
|
FirstChanceHandler handler) {
|
||||||
DCHECK(g_crash_handler);
|
DCHECK(SignalHandler::Get());
|
||||||
g_crash_handler->SetFirstChanceHandler(handler);
|
SignalHandler::Get()->SetFirstChanceHandler(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -55,59 +55,55 @@ namespace crashpad {
|
|||||||
namespace test {
|
namespace test {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct StartHandlerForSelfTestOptions {
|
||||||
|
bool start_handler_at_crash;
|
||||||
|
bool simulate_crash;
|
||||||
|
bool set_first_chance_handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StartHandlerForSelfTest
|
||||||
|
: public testing::TestWithParam<std::tuple<bool, bool, bool>> {
|
||||||
|
public:
|
||||||
|
StartHandlerForSelfTest() = default;
|
||||||
|
~StartHandlerForSelfTest() = default;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
std::tie(options_.start_handler_at_crash,
|
||||||
|
options_.simulate_crash,
|
||||||
|
options_.set_first_chance_handler) = GetParam();
|
||||||
|
}
|
||||||
|
|
||||||
|
const StartHandlerForSelfTestOptions& Options() const { return options_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StartHandlerForSelfTestOptions options_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StartHandlerForSelfTest);
|
||||||
|
};
|
||||||
|
|
||||||
bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) {
|
bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CrashpadClient, SimulateCrash) {
|
bool InstallHandler(CrashpadClient* client,
|
||||||
ScopedTempDir temp_dir;
|
bool start_at_crash,
|
||||||
|
const base::FilePath& handler_path,
|
||||||
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
|
const base::FilePath& database_path) {
|
||||||
FILE_PATH_LITERAL("crashpad_handler"));
|
return start_at_crash
|
||||||
|
? client->StartHandlerAtCrash(handler_path,
|
||||||
crashpad::CrashpadClient client;
|
database_path,
|
||||||
ASSERT_TRUE(client.StartHandlerAtCrash(handler_path,
|
|
||||||
base::FilePath(temp_dir.path()),
|
|
||||||
base::FilePath(),
|
base::FilePath(),
|
||||||
"",
|
"",
|
||||||
std::map<std::string, std::string>(),
|
std::map<std::string, std::string>(),
|
||||||
std::vector<std::string>()));
|
std::vector<std::string>())
|
||||||
|
: client->StartHandler(handler_path,
|
||||||
auto database =
|
database_path,
|
||||||
CrashReportDatabase::InitializeWithoutCreating(temp_dir.path());
|
base::FilePath(),
|
||||||
ASSERT_TRUE(database);
|
"",
|
||||||
|
std::map<std::string, std::string>(),
|
||||||
{
|
std::vector<std::string>(),
|
||||||
CrashpadClient::SetFirstChanceExceptionHandler(HandleCrashSuccessfully);
|
false,
|
||||||
|
false);
|
||||||
CRASHPAD_SIMULATE_CRASH();
|
|
||||||
|
|
||||||
std::vector<CrashReportDatabase::Report> reports;
|
|
||||||
ASSERT_EQ(database->GetPendingReports(&reports),
|
|
||||||
CrashReportDatabase::kNoError);
|
|
||||||
EXPECT_EQ(reports.size(), 0u);
|
|
||||||
|
|
||||||
reports.clear();
|
|
||||||
ASSERT_EQ(database->GetCompletedReports(&reports),
|
|
||||||
CrashReportDatabase::kNoError);
|
|
||||||
EXPECT_EQ(reports.size(), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
CrashpadClient::SetFirstChanceExceptionHandler(nullptr);
|
|
||||||
|
|
||||||
CRASHPAD_SIMULATE_CRASH();
|
|
||||||
|
|
||||||
std::vector<CrashReportDatabase::Report> reports;
|
|
||||||
ASSERT_EQ(database->GetPendingReports(&reports),
|
|
||||||
CrashReportDatabase::kNoError);
|
|
||||||
EXPECT_EQ(reports.size(), 1u);
|
|
||||||
|
|
||||||
reports.clear();
|
|
||||||
ASSERT_EQ(database->GetCompletedReports(&reports),
|
|
||||||
CrashReportDatabase::kNoError);
|
|
||||||
EXPECT_EQ(reports.size(), 0u);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr char kTestAnnotationName[] = "name_of_annotation";
|
constexpr char kTestAnnotationName[] = "name_of_annotation";
|
||||||
@ -152,7 +148,7 @@ void ValidateDump(const CrashReportDatabase::UploadReport* report) {
|
|||||||
ADD_FAILURE();
|
ADD_FAILURE();
|
||||||
}
|
}
|
||||||
|
|
||||||
CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) {
|
CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) {
|
||||||
FileHandle in = StdioFileHandle(StdioStream::kStandardInput);
|
FileHandle in = StdioFileHandle(StdioStream::kStandardInput);
|
||||||
|
|
||||||
VMSize temp_dir_length;
|
VMSize temp_dir_length;
|
||||||
@ -161,6 +157,9 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) {
|
|||||||
std::string temp_dir(temp_dir_length, '\0');
|
std::string temp_dir(temp_dir_length, '\0');
|
||||||
CheckedReadFileExactly(in, &temp_dir[0], temp_dir_length);
|
CheckedReadFileExactly(in, &temp_dir[0], temp_dir_length);
|
||||||
|
|
||||||
|
StartHandlerForSelfTestOptions options;
|
||||||
|
CheckedReadFileExactly(in, &options, sizeof(options));
|
||||||
|
|
||||||
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
|
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
|
||||||
FILE_PATH_LITERAL("crashpad_handler"));
|
FILE_PATH_LITERAL("crashpad_handler"));
|
||||||
|
|
||||||
@ -170,12 +169,10 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) {
|
|||||||
test_annotation.Set(kTestAnnotationValue);
|
test_annotation.Set(kTestAnnotationValue);
|
||||||
|
|
||||||
crashpad::CrashpadClient client;
|
crashpad::CrashpadClient client;
|
||||||
if (!client.StartHandlerAtCrash(handler_path,
|
if (!InstallHandler(&client,
|
||||||
base::FilePath(temp_dir),
|
options.start_handler_at_crash,
|
||||||
base::FilePath(),
|
handler_path,
|
||||||
"",
|
base::FilePath(temp_dir))) {
|
||||||
std::map<std::string, std::string>(),
|
|
||||||
std::vector<std::string>())) {
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,18 +182,29 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (options.simulate_crash) {
|
||||||
|
if (options.set_first_chance_handler) {
|
||||||
|
client.SetFirstChanceExceptionHandler(HandleCrashSuccessfully);
|
||||||
|
}
|
||||||
|
CRASHPAD_SIMULATE_CRASH();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
|
|
||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StartHandlerAtCrashTest : public MultiprocessExec {
|
class StartHandlerForSelfInChildTest : public MultiprocessExec {
|
||||||
public:
|
public:
|
||||||
StartHandlerAtCrashTest() : MultiprocessExec() {
|
StartHandlerForSelfInChildTest(const StartHandlerForSelfTestOptions& options)
|
||||||
SetChildTestMainFunction("StartHandlerAtCrashChild");
|
: MultiprocessExec(), options_(options) {
|
||||||
|
SetChildTestMainFunction("StartHandlerForSelfTestChild");
|
||||||
|
if (!options.simulate_crash) {
|
||||||
SetExpectedChildTerminationBuiltinTrap();
|
SetExpectedChildTerminationBuiltinTrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MultiprocessParent() override {
|
void MultiprocessParent() override {
|
||||||
@ -206,6 +214,8 @@ class StartHandlerAtCrashTest : public MultiprocessExec {
|
|||||||
WritePipeHandle(), &temp_dir_length, sizeof(temp_dir_length)));
|
WritePipeHandle(), &temp_dir_length, sizeof(temp_dir_length)));
|
||||||
ASSERT_TRUE(LoggingWriteFile(
|
ASSERT_TRUE(LoggingWriteFile(
|
||||||
WritePipeHandle(), temp_dir.path().value().data(), temp_dir_length));
|
WritePipeHandle(), temp_dir.path().value().data(), temp_dir_length));
|
||||||
|
ASSERT_TRUE(
|
||||||
|
LoggingWriteFile(WritePipeHandle(), &options_, sizeof(options_)));
|
||||||
|
|
||||||
// Wait for child to finish.
|
// Wait for child to finish.
|
||||||
CheckedReadFileAtEOF(ReadPipeHandle());
|
CheckedReadFileAtEOF(ReadPipeHandle());
|
||||||
@ -221,7 +231,11 @@ class StartHandlerAtCrashTest : public MultiprocessExec {
|
|||||||
reports.clear();
|
reports.clear();
|
||||||
ASSERT_EQ(database->GetPendingReports(&reports),
|
ASSERT_EQ(database->GetPendingReports(&reports),
|
||||||
CrashReportDatabase::kNoError);
|
CrashReportDatabase::kNoError);
|
||||||
ASSERT_EQ(reports.size(), 1u);
|
ASSERT_EQ(reports.size(), options_.set_first_chance_handler ? 0u : 1u);
|
||||||
|
|
||||||
|
if (options_.set_first_chance_handler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<const CrashReportDatabase::UploadReport> report;
|
std::unique_ptr<const CrashReportDatabase::UploadReport> report;
|
||||||
ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report),
|
ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report),
|
||||||
@ -229,14 +243,26 @@ class StartHandlerAtCrashTest : public MultiprocessExec {
|
|||||||
ValidateDump(report.get());
|
ValidateDump(report.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(StartHandlerAtCrashTest);
|
StartHandlerForSelfTestOptions options_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StartHandlerForSelfInChildTest);
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(CrashpadClient, StartHandlerAtCrash) {
|
TEST_P(StartHandlerForSelfTest, StartHandlerInChild) {
|
||||||
StartHandlerAtCrashTest test;
|
if (Options().set_first_chance_handler && !Options().simulate_crash) {
|
||||||
|
// TODO(jperaza): test first chance handlers with real crashes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StartHandlerForSelfInChildTest test(Options());
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(StartHandlerForSelfTestSuite,
|
||||||
|
StartHandlerForSelfTest,
|
||||||
|
testing::Combine(testing::Bool(),
|
||||||
|
testing::Bool(),
|
||||||
|
testing::Bool()));
|
||||||
|
|
||||||
// Test state for starting the handler for another process.
|
// Test state for starting the handler for another process.
|
||||||
class StartHandlerForClientTest {
|
class StartHandlerForClientTest {
|
||||||
public:
|
public:
|
||||||
|
@ -121,13 +121,6 @@ establish the Crashpad client environment before running a program.
|
|||||||
Either this option or **--mach-service**, but not both, is required. This
|
Either this option or **--mach-service**, but not both, is required. This
|
||||||
option is only valid on macOS.
|
option is only valid on macOS.
|
||||||
|
|
||||||
* **--no-identify-client-via-url**
|
|
||||||
|
|
||||||
Do not add client-identifying fields to the URL. By default, `"prod"`,
|
|
||||||
`"ver"`, and `"guid"` annotations are added to the upload URL as name-value
|
|
||||||
pairs `"product"`, `"version"`, and `"guid"`, respectively. Using this
|
|
||||||
option disables that behavior.
|
|
||||||
|
|
||||||
* **--initial-client-data**=*HANDLE_request_crash_dump*,*HANDLE_request_non_crash_dump*,*HANDLE_non_crash_dump_completed*,*HANDLE_first_pipe_instance*,*HANDLE_client_process*,*Address_crash_exception_information*,*Address_non_crash_exception_information*,*Address_debug_critical_section*
|
* **--initial-client-data**=*HANDLE_request_crash_dump*,*HANDLE_request_non_crash_dump*,*HANDLE_non_crash_dump_completed*,*HANDLE_first_pipe_instance*,*HANDLE_client_process*,*Address_crash_exception_information*,*Address_non_crash_exception_information*,*Address_debug_critical_section*
|
||||||
|
|
||||||
Register the initial client using the inherited handles and data provided.
|
Register the initial client using the inherited handles and data provided.
|
||||||
@ -141,6 +134,13 @@ establish the Crashpad client environment before running a program.
|
|||||||
client to register, and exits when all clients have exited, after waiting for
|
client to register, and exits when all clients have exited, after waiting for
|
||||||
any uploads in progress to complete.
|
any uploads in progress to complete.
|
||||||
|
|
||||||
|
* **--initial-client-fd**=_FD_
|
||||||
|
|
||||||
|
Wait for client requests on _FD_. Either this option or
|
||||||
|
**--trace-parent-with-exception**, but not both, is required. The handler
|
||||||
|
exits when all client connections have been closed. This option is only valid
|
||||||
|
on Linux platforms.
|
||||||
|
|
||||||
* **--mach-service**=_SERVICE_
|
* **--mach-service**=_SERVICE_
|
||||||
|
|
||||||
Check in with the bootstrap server under the name _SERVICE_. Either this
|
Check in with the bootstrap server under the name _SERVICE_. Either this
|
||||||
@ -198,6 +198,13 @@ establish the Crashpad client environment before running a program.
|
|||||||
To prevent excessive accumulation of handler processes, _ARGUMENT_ must not
|
To prevent excessive accumulation of handler processes, _ARGUMENT_ must not
|
||||||
be `--monitor-self`.
|
be `--monitor-self`.
|
||||||
|
|
||||||
|
* **--no-identify-client-via-url**
|
||||||
|
|
||||||
|
Do not add client-identifying fields to the URL. By default, `"prod"`,
|
||||||
|
`"ver"`, and `"guid"` annotations are added to the upload URL as name-value
|
||||||
|
pairs `"product"`, `"version"`, and `"guid"`, respectively. Using this
|
||||||
|
option disables that behavior.
|
||||||
|
|
||||||
* **--no-periodic-tasks**
|
* **--no-periodic-tasks**
|
||||||
|
|
||||||
Do not scan for new pending crash reports or prune the crash report database.
|
Do not scan for new pending crash reports or prune the crash report database.
|
||||||
@ -245,17 +252,24 @@ establish the Crashpad client environment before running a program.
|
|||||||
parent process. This option is only valid on macOS. Use of this option is
|
parent process. This option is only valid on macOS. Use of this option is
|
||||||
discouraged. It should not be used absent extraordinary circumstances.
|
discouraged. It should not be used absent extraordinary circumstances.
|
||||||
|
|
||||||
|
* **--sanitization-information**=_SANITIZATION-INFORMATION-ADDRESS_
|
||||||
|
|
||||||
|
Provides sanitization settings in a SanitizationInformation struct at
|
||||||
|
_SANITIZATION-INFORMATION-ADDRESS_. This option requires
|
||||||
|
**--trace-parent-with-exception** and is only valid on Linux platforms.
|
||||||
|
|
||||||
|
* **--shared-client-connection**
|
||||||
|
|
||||||
|
Indicates that the file descriptor provided by **--initial-client-fd** is
|
||||||
|
shared among mulitple clients. Using a broker process is not supported for
|
||||||
|
clients using this option. This option is only valid on Linux platforms.
|
||||||
|
|
||||||
* **--trace-parent-with-exception**=_EXCEPTION-INFORMATION-ADDRESS_
|
* **--trace-parent-with-exception**=_EXCEPTION-INFORMATION-ADDRESS_
|
||||||
|
|
||||||
Causes the handler process to trace its parent process and exit. The parent
|
Causes the handler process to trace its parent process and exit. The parent
|
||||||
process should have an ExceptionInformation struct at
|
process should have an ExceptionInformation struct at
|
||||||
_EXCEPTION-INFORMATION-ADDRESS_.
|
_EXCEPTION-INFORMATION-ADDRESS_. This option is only valid on Linux
|
||||||
|
platforms.
|
||||||
* **--initial-client-fd**=_FD_
|
|
||||||
|
|
||||||
Starts the excetion handler server with an initial ExceptionHandlerClient
|
|
||||||
connected on the socket _FD_. The server will exit when all connected client
|
|
||||||
sockets have been closed.
|
|
||||||
|
|
||||||
* **--url**=_URL_
|
* **--url**=_URL_
|
||||||
|
|
||||||
|
@ -118,6 +118,9 @@ void Usage(const base::FilePath& me) {
|
|||||||
" Address_debug_critical_section\n"
|
" Address_debug_critical_section\n"
|
||||||
" use precreated data to register initial client\n"
|
" use precreated data to register initial client\n"
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
|
#if defined(OS_ANDROID) || defined(OS_LINUX)
|
||||||
|
" --initial-client-fd=FD a socket connected to a client.\n"
|
||||||
|
#endif // OS_ANDROID || OS_LINUX
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
" --mach-service=SERVICE register SERVICE with the bootstrap server\n"
|
" --mach-service=SERVICE register SERVICE with the bootstrap server\n"
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
@ -141,11 +144,13 @@ void Usage(const base::FilePath& me) {
|
|||||||
" reset the server's exception handler to default\n"
|
" reset the server's exception handler to default\n"
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
|
" --sanitization-information=SANITIZATION_INFORMATION_ADDRESS\n"
|
||||||
|
" the address of a SanitizationInformation struct.\n"
|
||||||
|
" --shared-client-connection the file descriptor provided by\n"
|
||||||
|
" --initial-client-fd is shared among multiple\n"
|
||||||
|
" clients\n"
|
||||||
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
|
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
|
||||||
" request a dump for the handler's parent process\n"
|
" request a dump for the handler's parent process\n"
|
||||||
" --initial-client-fd=FD a socket connected to a client.\n"
|
|
||||||
" --sanitization_information=SANITIZATION_INFORMATION_ADDRESS\n"
|
|
||||||
" the address of a SanitizationInformation struct.\n"
|
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
" --url=URL send crash reports to this Breakpad server URL,\n"
|
" --url=URL send crash reports to this Breakpad server URL,\n"
|
||||||
" only if uploads are enabled for the database\n"
|
" only if uploads are enabled for the database\n"
|
||||||
@ -168,8 +173,9 @@ struct Options {
|
|||||||
bool reset_own_crash_exception_port_to_system_default;
|
bool reset_own_crash_exception_port_to_system_default;
|
||||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
VMAddress exception_information_address;
|
VMAddress exception_information_address;
|
||||||
int initial_client_fd;
|
|
||||||
VMAddress sanitization_information_address;
|
VMAddress sanitization_information_address;
|
||||||
|
int initial_client_fd;
|
||||||
|
bool shared_client_connection;
|
||||||
#elif defined(OS_WIN)
|
#elif defined(OS_WIN)
|
||||||
std::string pipe_name;
|
std::string pipe_name;
|
||||||
InitialClientData initial_client_data;
|
InitialClientData initial_client_data;
|
||||||
@ -530,6 +536,9 @@ int HandlerMain(int argc,
|
|||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
kOptionInitialClientData,
|
kOptionInitialClientData,
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
|
#if defined(OS_ANDROID) || defined(OS_LINUX)
|
||||||
|
kOptionInitialClientFD,
|
||||||
|
#endif // OS_ANDROID || OS_LINUX
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
kOptionMachService,
|
kOptionMachService,
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
@ -548,9 +557,9 @@ int HandlerMain(int argc,
|
|||||||
kOptionResetOwnCrashExceptionPortToSystemDefault,
|
kOptionResetOwnCrashExceptionPortToSystemDefault,
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
kOptionTraceParentWithException,
|
|
||||||
kOptionInitialClientFD,
|
|
||||||
kOptionSanitizationInformation,
|
kOptionSanitizationInformation,
|
||||||
|
kOptionSharedClientConnection,
|
||||||
|
kOptionTraceParentWithException,
|
||||||
#endif
|
#endif
|
||||||
kOptionURL,
|
kOptionURL,
|
||||||
|
|
||||||
@ -571,6 +580,9 @@ int HandlerMain(int argc,
|
|||||||
nullptr,
|
nullptr,
|
||||||
kOptionInitialClientData},
|
kOptionInitialClientData},
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
|
#if defined(OS_ANDROID) || defined(OS_LINUX)
|
||||||
|
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
|
||||||
|
#endif // OS_ANDROID || OS_LINUX
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
{"mach-service", required_argument, nullptr, kOptionMachService},
|
{"mach-service", required_argument, nullptr, kOptionMachService},
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
@ -601,15 +613,18 @@ int HandlerMain(int argc,
|
|||||||
kOptionResetOwnCrashExceptionPortToSystemDefault},
|
kOptionResetOwnCrashExceptionPortToSystemDefault},
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
{"trace-parent-with-exception",
|
|
||||||
required_argument,
|
|
||||||
nullptr,
|
|
||||||
kOptionTraceParentWithException},
|
|
||||||
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
|
|
||||||
{"sanitization-information",
|
{"sanitization-information",
|
||||||
required_argument,
|
required_argument,
|
||||||
nullptr,
|
nullptr,
|
||||||
kOptionSanitizationInformation},
|
kOptionSanitizationInformation},
|
||||||
|
{"shared-client-connection",
|
||||||
|
no_argument,
|
||||||
|
nullptr,
|
||||||
|
kOptionSharedClientConnection},
|
||||||
|
{"trace-parent-with-exception",
|
||||||
|
required_argument,
|
||||||
|
nullptr,
|
||||||
|
kOptionTraceParentWithException},
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
{"url", required_argument, nullptr, kOptionURL},
|
{"url", required_argument, nullptr, kOptionURL},
|
||||||
{"help", no_argument, nullptr, kOptionHelp},
|
{"help", no_argument, nullptr, kOptionHelp},
|
||||||
@ -622,14 +637,12 @@ int HandlerMain(int argc,
|
|||||||
options.handshake_fd = -1;
|
options.handshake_fd = -1;
|
||||||
#endif
|
#endif
|
||||||
options.identify_client_via_url = true;
|
options.identify_client_via_url = true;
|
||||||
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
|
options.initial_client_fd = kInvalidFileHandle;
|
||||||
|
#endif
|
||||||
options.periodic_tasks = true;
|
options.periodic_tasks = true;
|
||||||
options.rate_limit = true;
|
options.rate_limit = true;
|
||||||
options.upload_gzip = true;
|
options.upload_gzip = true;
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
|
||||||
options.exception_information_address = 0;
|
|
||||||
options.initial_client_fd = kInvalidFileHandle;
|
|
||||||
options.sanitization_information_address = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
||||||
@ -670,6 +683,15 @@ int HandlerMain(int argc,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
|
#if defined(OS_ANDROID) || defined(OS_LINUX)
|
||||||
|
case kOptionInitialClientFD: {
|
||||||
|
if (!base::StringToInt(optarg, &options.initial_client_fd)) {
|
||||||
|
ToolSupport::UsageHint(me, "failed to parse --initial-client-fd");
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif // OS_ANDROID || OS_LINUX
|
||||||
case kOptionMetrics: {
|
case kOptionMetrics: {
|
||||||
options.metrics_dir = base::FilePath(
|
options.metrics_dir = base::FilePath(
|
||||||
ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
|
ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
|
||||||
@ -720,21 +742,6 @@ int HandlerMain(int argc,
|
|||||||
}
|
}
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
case kOptionTraceParentWithException: {
|
|
||||||
if (!StringToNumber(optarg, &options.exception_information_address)) {
|
|
||||||
ToolSupport::UsageHint(
|
|
||||||
me, "failed to parse --trace-parent-with-exception");
|
|
||||||
return ExitFailure();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kOptionInitialClientFD: {
|
|
||||||
if (!base::StringToInt(optarg, &options.initial_client_fd)) {
|
|
||||||
ToolSupport::UsageHint(me, "failed to parse --initial-client-fd");
|
|
||||||
return ExitFailure();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kOptionSanitizationInformation: {
|
case kOptionSanitizationInformation: {
|
||||||
if (!StringToNumber(optarg,
|
if (!StringToNumber(optarg,
|
||||||
&options.sanitization_information_address)) {
|
&options.sanitization_information_address)) {
|
||||||
@ -744,6 +751,18 @@ int HandlerMain(int argc,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kOptionSharedClientConnection: {
|
||||||
|
options.shared_client_connection = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kOptionTraceParentWithException: {
|
||||||
|
if (!StringToNumber(optarg, &options.exception_information_address)) {
|
||||||
|
ToolSupport::UsageHint(
|
||||||
|
me, "failed to parse --trace-parent-with-exception");
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
case kOptionURL: {
|
case kOptionURL: {
|
||||||
options.url = optarg;
|
options.url = optarg;
|
||||||
@ -793,7 +812,7 @@ int HandlerMain(int argc,
|
|||||||
if (!options.exception_information_address &&
|
if (!options.exception_information_address &&
|
||||||
options.initial_client_fd == kInvalidFileHandle) {
|
options.initial_client_fd == kInvalidFileHandle) {
|
||||||
ToolSupport::UsageHint(
|
ToolSupport::UsageHint(
|
||||||
me, "--trace-parent-with-exception or --initial_client_fd is required");
|
me, "--trace-parent-with-exception or --initial-client-fd is required");
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
if (options.sanitization_information_address &&
|
if (options.sanitization_information_address &&
|
||||||
@ -803,6 +822,12 @@ int HandlerMain(int argc,
|
|||||||
"--sanitization_information requires --trace-parent-with-exception");
|
"--sanitization_information requires --trace-parent-with-exception");
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
|
if (options.shared_client_connection &&
|
||||||
|
options.initial_client_fd == kInvalidFileHandle) {
|
||||||
|
ToolSupport::UsageHint(
|
||||||
|
me, "--shared-client-connection requires --initial-client-fd");
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
|
|
||||||
if (options.database.empty()) {
|
if (options.database.empty()) {
|
||||||
@ -994,7 +1019,8 @@ int HandlerMain(int argc,
|
|||||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
if (options.initial_client_fd == kInvalidFileHandle ||
|
if (options.initial_client_fd == kInvalidFileHandle ||
|
||||||
!exception_handler_server.InitializeWithClient(
|
!exception_handler_server.InitializeWithClient(
|
||||||
ScopedFileHandle(options.initial_client_fd), false)) {
|
ScopedFileHandle(options.initial_client_fd),
|
||||||
|
options.shared_client_connection)) {
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
|
Loading…
x
Reference in New Issue
Block a user