Skip to content

Commit

Permalink
Add handler options for Linux/Android
Browse files Browse the repository at this point in the history
Add the options:
--trace-parent-with-exception=<address>
  which traces the handler's parent process which has an
  ExceptionInformation struct at <address>.
--initial-client-fd=<fd>
  which starts the handler server with an already connected client on
  socket <fd>.

Bug: crashpad:30
Change-Id: Ied9760ca125a16f56173afdc56dff5fcb79d2eea
Reviewed-on: https://chromium-review.googlesource.com/922895
Commit-Queue: Joshua Peraza <[email protected]>
Reviewed-by: Mark Mentovai <[email protected]>
  • Loading branch information
Joshua Peraza authored and Commit Bot committed Feb 20, 2018
1 parent 0520fdf commit 38540ea
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 47 deletions.
19 changes: 19 additions & 0 deletions handler/crashpad_handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ when run normally from a shell using only the basename (without an explicit
stdio will be hooked up as expected to the parent console so that logging output
will be visible.

On Linux/Android, the handler may create a crash dump for its parent process
using **--trace-parent-with-exception**. In this mode, the handler process
creates a crash dump for its parent and exits. Alternatively, the handler may
be launched with **--initial-client-fd** which will start the server connected
to an initial client. The server will exit when all connected client sockets are
closed.

It is not normally appropriate to invoke this program directly. Usually, it will
be invoked by a Crashpad client using the Crashpad client library, or started by
another system service. On macOS, arbitrary programs may be run with a Crashpad
Expand Down Expand Up @@ -238,6 +245,18 @@ establish the Crashpad client environment before running a program.
parent process. This option is only valid on macOS. Use of this option is
discouraged. It should not be used absent extraordinary circumstances.

* **--trace-parent-with-exception**=_EXCEPTION-INFORMATION-ADDRESS_

Causes the handler process to trace its parent process and exit. The parent
process should have an ExceptionInformation struct at
_EXCEPTION-INFORMATION-ADDRESS_.

* **--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_

If uploads are enabled, sends crash reports to the Breakpad-type crash report
Expand Down
7 changes: 0 additions & 7 deletions handler/handler.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@
'win/crash_report_exception_handler.cc',
'win/crash_report_exception_handler.h',
],
'conditions': [
['OS=="android"', {
'sources!': [
'handler_main.cc',
],
}],
],
'target_conditions': [
['OS=="android"', {
'sources/': [
Expand Down
184 changes: 144 additions & 40 deletions handler/handler_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "base/logging.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/scoped_generic.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
Expand All @@ -46,6 +47,7 @@
#include "handler/prune_crash_reports_thread.h"
#include "tools/tool_support.h"
#include "util/file/file_io.h"
#include "util/misc/address_types.h"
#include "util/misc/metrics.h"
#include "util/misc/paths.h"
#include "util/numeric/in_range_cast.h"
Expand All @@ -54,7 +56,13 @@
#include "util/string/split_string.h"
#include "util/synchronization/semaphore.h"

#if defined(OS_MACOSX)
#if defined(OS_LINUX) || defined(OS_ANDROID)
#include <unistd.h>

#include "handler/linux/crash_report_exception_handler.h"
#include "handler/linux/exception_handler_server.h"
#include "util/posix/signals.h"
#elif defined(OS_MACOSX)
#include <libgen.h>
#include <signal.h>

Expand Down Expand Up @@ -129,6 +137,11 @@ void Usage(const base::FilePath& me) {
" --reset-own-crash-exception-port-to-system-default\n"
" reset the server's exception handler to default\n"
#endif // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
" request a dump for the handler's parent process\n"
" --initial-client-fd=FD a socket connected to a client.\n"
#endif // OS_LINUX || OS_ANDROID
" --url=URL send crash reports to this Breakpad server URL,\n"
" only if uploads are enabled for the database\n"
" --help display this help and exit\n"
Expand All @@ -148,6 +161,9 @@ struct Options {
std::string mach_service;
int handshake_fd;
bool reset_own_crash_exception_port_to_system_default;
#elif defined(OS_LINUX) || defined(OS_ANDROID)
VMAddress exception_information_address;
int initial_client_fd;
#elif defined(OS_WIN)
std::string pipe_name;
InitialClientData initial_client_data;
Expand Down Expand Up @@ -214,7 +230,9 @@ class CallMetricsRecordNormalExit {
DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit);
};

#if defined(OS_MACOSX)
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID)

Signals::OldActions g_old_crash_signal_handlers;

void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
Expand Down Expand Up @@ -250,14 +268,18 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
}
Metrics::HandlerCrashed(metrics_code);

Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
struct sigaction* old_action =
g_old_crash_signal_handlers.ActionForSignal(sig);
Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action);
}

void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
}

#if defined(OS_MACOSX)

void ReinstallCrashHandler() {
// This is used to re-enable the metrics-recording crash handler after
// MonitorSelf() sets up a Crashpad exception handler. On macOS, the
Expand Down Expand Up @@ -296,6 +318,23 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
g_exception_handler_server->Stop();
}

#else

void ReinstallCrashHandler() {
// This is used to re-enable the metrics-recording crash handler after
// MonitorSelf() sets up a Crashpad signal handler.
Signals::InstallCrashHandlers(
HandleCrashSignal, 0, &g_old_crash_signal_handlers);
}

void InstallCrashHandler() {
ReinstallCrashHandler();

Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr);
}

#endif // OS_MACOSX

#elif defined(OS_WIN)

LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr;
Expand Down Expand Up @@ -401,6 +440,16 @@ void MonitorSelf(const Options& options) {
// instance of crashpad_handler to be writing metrics at a time, and it should
// be the primary instance.
CrashpadClient crashpad_client;
#if defined(OS_LINUX) || defined(OS_ANDROID)
if (!crashpad_client.StartHandlerAtCrash(executable_path,
options.database,
base::FilePath(),
options.url,
options.annotations,
extra_arguments)) {
return;
}
#else
if (!crashpad_client.StartHandler(executable_path,
options.database,
base::FilePath(),
Expand All @@ -411,6 +460,7 @@ void MonitorSelf(const Options& options) {
false)) {
return;
}
#endif

// Make sure that appropriate metrics will be recorded on crash before this
// process is terminated.
Expand Down Expand Up @@ -477,6 +527,10 @@ int HandlerMain(int argc,
#if defined(OS_MACOSX)
kOptionResetOwnCrashExceptionPortToSystemDefault,
#endif // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
kOptionTraceParentWithException,
kOptionInitialClientFD,
#endif
kOptionURL,

// Standard options.
Expand Down Expand Up @@ -525,6 +579,13 @@ int HandlerMain(int argc,
nullptr,
kOptionResetOwnCrashExceptionPortToSystemDefault},
#endif // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
{"trace-parent-with-exception",
required_argument,
nullptr,
kOptionTraceParentWithException},
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
#endif // OS_LINUX || OS_ANDROID
{"url", required_argument, nullptr, kOptionURL},
{"help", no_argument, nullptr, kOptionHelp},
{"version", no_argument, nullptr, kOptionVersion},
Expand All @@ -539,6 +600,10 @@ int HandlerMain(int argc,
options.periodic_tasks = true;
options.rate_limit = true;
options.upload_gzip = true;
#if defined(OS_LINUX) || defined(OS_ANDROID)
options.exception_information_address = 0;
options.initial_client_fd = kInvalidFileHandle;
#endif

int opt;
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
Expand Down Expand Up @@ -628,6 +693,23 @@ int HandlerMain(int argc,
break;
}
#endif // OS_MACOSX
#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;
}
#endif // OS_LINUX || OS_ANDROID
case kOptionURL: {
options.url = optarg;
break;
Expand Down Expand Up @@ -672,6 +754,14 @@ int HandlerMain(int argc,
me, "--initial-client-data and --pipe-name are incompatible");
return ExitFailure();
}
#elif defined(OS_LINUX) || defined(OS_ANDROID)
if (!options.exception_information_address &&
options.initial_client_fd == kInvalidFileHandle) {
ToolSupport::UsageHint(
me,
"--exception_information_address or --initial_client_fd is required");
return ExitFailure();
}
#endif // OS_MACOSX

if (options.database.empty()) {
Expand Down Expand Up @@ -714,6 +804,50 @@ int HandlerMain(int argc,
}
}

std::unique_ptr<CrashReportDatabase> database(
CrashReportDatabase::Initialize(options.database));
if (!database) {
return ExitFailure();
}

ScopedStoppable upload_thread;
if (!options.url.empty()) {
// TODO(scottmg): options.rate_limit should be removed when we have a
// configurable database setting to control upload limiting.
// See https://crashpad.chromium.org/bug/23.
CrashReportUploadThread::Options upload_thread_options;
upload_thread_options.identify_client_via_url =
options.identify_client_via_url;
upload_thread_options.rate_limit = options.rate_limit;
upload_thread_options.upload_gzip = options.upload_gzip;
upload_thread_options.watch_pending_reports = options.periodic_tasks;

upload_thread.Reset(new CrashReportUploadThread(
database.get(), options.url, upload_thread_options));
upload_thread.Get()->Start();
}

CrashReportExceptionHandler exception_handler(
database.get(),
static_cast<CrashReportUploadThread*>(upload_thread.Get()),
&options.annotations,
user_stream_sources);

#if defined(OS_LINUX) || defined(OS_ANDROID)
if (options.exception_information_address) {
return exception_handler.HandleException(getppid(),
options.exception_information_address) ?
EXIT_SUCCESS : ExitFailure();
}
#endif // OS_LINUX || OS_ANDROID

ScopedStoppable prune_thread;
if (options.periodic_tasks) {
prune_thread.Reset(new PruneCrashReportThread(
database.get(), PruneCondition::GetDefault()));
prune_thread.Get()->Start();
}

#if defined(OS_MACOSX)
if (options.mach_service.empty()) {
// Don’t do this when being run by launchd. See launchd.plist(5).
Expand Down Expand Up @@ -767,7 +901,7 @@ int HandlerMain(int argc,
if (!options.pipe_name.empty()) {
exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
}
#elif defined(OS_FUCHSIA) || defined(OS_LINUX)
#elif defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
ExceptionHandlerServer exception_handler_server;
#endif // OS_MACOSX

Expand All @@ -784,47 +918,17 @@ int HandlerMain(int argc,

Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);

std::unique_ptr<CrashReportDatabase> database(
CrashReportDatabase::Initialize(options.database));
if (!database) {
return ExitFailure();
}

ScopedStoppable upload_thread;
if (!options.url.empty()) {
// TODO(scottmg): options.rate_limit should be removed when we have a
// configurable database setting to control upload limiting.
// See https://crashpad.chromium.org/bug/23.
CrashReportUploadThread::Options upload_thread_options;
upload_thread_options.identify_client_via_url =
options.identify_client_via_url;
upload_thread_options.rate_limit = options.rate_limit;
upload_thread_options.upload_gzip = options.upload_gzip;
upload_thread_options.watch_pending_reports = options.periodic_tasks;

upload_thread.Reset(new CrashReportUploadThread(
database.get(), options.url, upload_thread_options));
upload_thread.Get()->Start();
}

ScopedStoppable prune_thread;
if (options.periodic_tasks) {
prune_thread.Reset(new PruneCrashReportThread(
database.get(), PruneCondition::GetDefault()));
prune_thread.Get()->Start();
}

CrashReportExceptionHandler exception_handler(
database.get(),
static_cast<CrashReportUploadThread*>(upload_thread.Get()),
&options.annotations,
user_stream_sources);

#if defined(OS_WIN)
if (options.initial_client_data.IsValid()) {
exception_handler_server.InitializeWithInheritedDataForInitialClient(
options.initial_client_data, &exception_handler);
}
#elif defined(OS_LINUX) || defined(OS_ANDROID)
if (options.initial_client_fd == kInvalidFileHandle ||
!exception_handler_server.InitializeWithClient(
ScopedFileHandle(options.initial_client_fd))) {
return ExitFailure();
}
#endif // OS_WIN

exception_handler_server.Run(&exception_handler);
Expand Down

0 comments on commit 38540ea

Please sign in to comment.