mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add handler options for Linux/Android
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 <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
0520fdff1e
commit
38540eaf71
@ -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
|
||||
@ -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
|
||||
|
@ -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/': [
|
||||
|
@ -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"
|
||||
@ -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"
|
||||
@ -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>
|
||||
|
||||
@ -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"
|
||||
@ -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;
|
||||
@ -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);
|
||||
@ -250,7 +268,9 @@ 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) {
|
||||
@ -258,6 +278,8 @@ void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
|
||||
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
|
||||
@ -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;
|
||||
@ -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(),
|
||||
@ -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.
|
||||
@ -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.
|
||||
@ -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},
|
||||
@ -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) {
|
||||
@ -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;
|
||||
@ -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()) {
|
||||
@ -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).
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user