| Index: third_party/crashpad/crashpad/handler/handler_main.cc
|
| diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc
|
| index 16eb11426d2f9125e6670877d33abf269cc1fced..f58f1ba4cd05862e23f6fdb4967f16cb9b7e87ef 100644
|
| --- a/third_party/crashpad/crashpad/handler/handler_main.cc
|
| +++ b/third_party/crashpad/crashpad/handler/handler_main.cc
|
| @@ -20,6 +20,7 @@
|
| #include <stdlib.h>
|
| #include <sys/types.h>
|
|
|
| +#include <algorithm>
|
| #include <map>
|
| #include <memory>
|
| #include <string>
|
| @@ -33,16 +34,20 @@
|
| #include "base/logging.h"
|
| #include "base/metrics/persistent_histogram_allocator.h"
|
| #include "base/scoped_generic.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "build/build_config.h"
|
| #include "client/crash_report_database.h"
|
| #include "client/crashpad_client.h"
|
| +#include "client/crashpad_info.h"
|
| #include "client/prune_crash_reports.h"
|
| +#include "client/simple_string_dictionary.h"
|
| #include "handler/crash_report_upload_thread.h"
|
| #include "handler/prune_crash_reports_thread.h"
|
| #include "tools/tool_support.h"
|
| #include "util/file/file_io.h"
|
| #include "util/misc/metrics.h"
|
| +#include "util/misc/paths.h"
|
| #include "util/numeric/in_range_cast.h"
|
| #include "util/stdlib/map_insert.h"
|
| #include "util/stdlib/string_number_conversion.h"
|
| @@ -83,8 +88,8 @@ void Usage(const base::FilePath& me) {
|
| " --database=PATH store the crash report database at PATH\n"
|
| #if defined(OS_MACOSX)
|
| " --handshake-fd=FD establish communication with the client over FD\n"
|
| -" --mach-service=SERVICE register SERVICE with the bootstrap server\n"
|
| -#elif defined(OS_WIN)
|
| +#endif // OS_MACOSX
|
| +#if defined(OS_WIN)
|
| " --initial-client-data=HANDLE_request_crash_dump,\n"
|
| " HANDLE_request_non_crash_dump,\n"
|
| " HANDLE_non_crash_dump_completed,\n"
|
| @@ -94,15 +99,24 @@ void Usage(const base::FilePath& me) {
|
| " Address_non_crash_exception_information,\n"
|
| " Address_debug_critical_section\n"
|
| " use precreated data to register initial client\n"
|
| +#endif // OS_WIN
|
| +#if defined(OS_MACOSX)
|
| +" --mach-service=SERVICE register SERVICE with the bootstrap server\n"
|
| #endif // OS_MACOSX
|
| " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n"
|
| +" --monitor-self run a second handler to catch crashes in the first\n"
|
| +" --monitor-self-annotation=KEY=VALUE\n"
|
| +" set a module annotation in the handler\n"
|
| +" --monitor-self-argument=ARGUMENT\n"
|
| +" provide additional arguments to the second handler\n"
|
| " --no-rate-limit don't rate limit crash uploads\n"
|
| " --no-upload-gzip don't use gzip compression when uploading\n"
|
| +#if defined(OS_WIN)
|
| +" --pipe-name=PIPE communicate with the client over PIPE\n"
|
| +#endif // OS_WIN
|
| #if defined(OS_MACOSX)
|
| " --reset-own-crash-exception-port-to-system-default\n"
|
| " reset the server's exception handler to default\n"
|
| -#elif defined(OS_WIN)
|
| -" --pipe-name=PIPE communicate with the client over PIPE\n"
|
| #endif // OS_MACOSX
|
| " --url=URL send crash reports to this Breakpad server URL,\n"
|
| " only if uploads are enabled for the database\n"
|
| @@ -112,6 +126,49 @@ void Usage(const base::FilePath& me) {
|
| ToolSupport::UsageTail(me);
|
| }
|
|
|
| +struct Options {
|
| + std::map<std::string, std::string> annotations;
|
| + std::map<std::string, std::string> monitor_self_annotations;
|
| + std::string url;
|
| + base::FilePath database;
|
| + base::FilePath metrics_dir;
|
| + std::vector<std::string> monitor_self_arguments;
|
| +#if defined(OS_MACOSX)
|
| + std::string mach_service;
|
| + int handshake_fd;
|
| + bool reset_own_crash_exception_port_to_system_default;
|
| +#elif defined(OS_WIN)
|
| + std::string pipe_name;
|
| + InitialClientData initial_client_data;
|
| +#endif // OS_MACOSX
|
| + bool monitor_self;
|
| + bool rate_limit;
|
| + bool upload_gzip;
|
| +};
|
| +
|
| +// Splits |key_value| on '=' and inserts the resulting key and value into |map|.
|
| +// If |key_value| has the wrong format, logs an error and returns false. If the
|
| +// key is already in the map, logs a warning, replaces the existing value, and
|
| +// returns true. If the key and value were inserted into the map, returns true.
|
| +// |argument| is used to give context to logged messages.
|
| +bool AddKeyValueToMap(std::map<std::string, std::string>* map,
|
| + const std::string& key_value,
|
| + const char* argument) {
|
| + std::string key;
|
| + std::string value;
|
| + if (!SplitStringFirst(key_value, '=', &key, &value)) {
|
| + LOG(ERROR) << argument << " requires KEY=VALUE";
|
| + return false;
|
| + }
|
| +
|
| + std::string old_value;
|
| + if (!MapInsertOrReplace(map, key, value, &old_value)) {
|
| + LOG(WARNING) << argument << " has duplicate key " << key
|
| + << ", discarding value " << old_value;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
|
| // to prevent multiple exit events from inadvertently being recorded, which
|
| // might happen if a crash occurs during destruction in what would otherwise be
|
| @@ -188,6 +245,13 @@ void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
|
| Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
|
| }
|
|
|
| +void ReinstallCrashHandler() {
|
| + // This is used to re-enable the metrics-recording crash handler after
|
| + // MonitorSelf() sets up a Crashpad exception handler. On macOS, the
|
| + // metrics-recording handler uses signals and the Crashpad handler uses Mach
|
| + // exceptions, so there’s nothing to re-enable.
|
| +}
|
| +
|
| void InstallCrashHandler() {
|
| Signals::InstallCrashHandlers(HandleCrashSignal, 0, nullptr);
|
|
|
| @@ -254,9 +318,17 @@ class TerminateHandler final : public SessionEndWatcher {
|
| DISALLOW_COPY_AND_ASSIGN(TerminateHandler);
|
| };
|
|
|
| -void InstallCrashHandler() {
|
| +void ReinstallCrashHandler() {
|
| + // This is used to re-enable the metrics-recording crash handler after
|
| + // MonitorSelf() sets up a Crashpad exception handler. The Crashpad handler
|
| + // takes over the UnhandledExceptionFilter, so reinstall the metrics-recording
|
| + // one.
|
| g_original_exception_filter =
|
| SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
|
| +}
|
| +
|
| +void InstallCrashHandler() {
|
| + ReinstallCrashHandler();
|
|
|
| // These are termination handlers, not crash handlers, but that’s close
|
| // enough. Note that destroying the TerminateHandler would wait for its thread
|
| @@ -268,6 +340,52 @@ void InstallCrashHandler() {
|
|
|
| #endif // OS_MACOSX
|
|
|
| +void MonitorSelf(const Options& options) {
|
| + base::FilePath executable_path;
|
| + if (!Paths::Executable(&executable_path)) {
|
| + return;
|
| + }
|
| +
|
| + if (std::find(options.monitor_self_arguments.begin(),
|
| + options.monitor_self_arguments.end(),
|
| + "--monitor-self") != options.monitor_self_arguments.end()) {
|
| + LOG(WARNING) << "--monitor-self-argument=--monitor-self is not supported";
|
| + return;
|
| + }
|
| + std::vector<std::string> extra_arguments(options.monitor_self_arguments);
|
| + if (!options.rate_limit) {
|
| + extra_arguments.push_back("--no-rate-limit");
|
| + }
|
| + if (!options.upload_gzip) {
|
| + extra_arguments.push_back("--no-upload-gzip");
|
| + }
|
| + for (const auto& iterator : options.monitor_self_annotations) {
|
| + extra_arguments.push_back(
|
| + base::StringPrintf("--monitor-self-annotation=%s=%s",
|
| + iterator.first.c_str(),
|
| + iterator.second.c_str()));
|
| + }
|
| +
|
| + // Don’t use options.metrics_dir. The current implementation only allows one
|
| + // instance of crashpad_handler to be writing metrics at a time, and it should
|
| + // be the primary instance.
|
| + CrashpadClient crashpad_client;
|
| + if (!crashpad_client.StartHandler(executable_path,
|
| + options.database,
|
| + base::FilePath(),
|
| + options.url,
|
| + options.annotations,
|
| + extra_arguments,
|
| + true,
|
| + false)) {
|
| + return;
|
| + }
|
| +
|
| + // Make sure that appropriate metrics will be recorded on crash before this
|
| + // process is terminated.
|
| + ReinstallCrashHandler();
|
| +}
|
| +
|
| } // namespace
|
|
|
| int HandlerMain(int argc, char* argv[]) {
|
| @@ -293,12 +411,16 @@ int HandlerMain(int argc, char* argv[]) {
|
| kOptionMachService,
|
| #endif // OS_MACOSX
|
| kOptionMetrics,
|
| + kOptionMonitorSelf,
|
| + kOptionMonitorSelfAnnotation,
|
| + kOptionMonitorSelfArgument,
|
| kOptionNoRateLimit,
|
| kOptionNoUploadGzip,
|
| +#if defined(OS_WIN)
|
| + kOptionPipeName,
|
| +#endif // OS_WIN
|
| #if defined(OS_MACOSX)
|
| kOptionResetOwnCrashExceptionPortToSystemDefault,
|
| -#elif defined(OS_WIN)
|
| - kOptionPipeName,
|
| #endif // OS_MACOSX
|
| kOptionURL,
|
|
|
| @@ -307,28 +429,6 @@ int HandlerMain(int argc, char* argv[]) {
|
| kOptionVersion = -3,
|
| };
|
|
|
| - struct {
|
| - std::map<std::string, std::string> annotations;
|
| - std::string url;
|
| - const char* database;
|
| - const char* metrics;
|
| -#if defined(OS_MACOSX)
|
| - int handshake_fd;
|
| - std::string mach_service;
|
| - bool reset_own_crash_exception_port_to_system_default;
|
| -#elif defined(OS_WIN)
|
| - std::string pipe_name;
|
| - InitialClientData initial_client_data;
|
| -#endif // OS_MACOSX
|
| - bool rate_limit;
|
| - bool upload_gzip;
|
| - } options = {};
|
| -#if defined(OS_MACOSX)
|
| - options.handshake_fd = -1;
|
| -#endif
|
| - options.rate_limit = true;
|
| - options.upload_gzip = true;
|
| -
|
| const option long_options[] = {
|
| {"annotation", required_argument, nullptr, kOptionAnnotation},
|
| {"database", required_argument, nullptr, kOptionDatabase},
|
| @@ -345,15 +445,25 @@ int HandlerMain(int argc, char* argv[]) {
|
| {"mach-service", required_argument, nullptr, kOptionMachService},
|
| #endif // OS_MACOSX
|
| {"metrics-dir", required_argument, nullptr, kOptionMetrics},
|
| + {"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
|
| + {"monitor-self-annotation",
|
| + required_argument,
|
| + nullptr,
|
| + kOptionMonitorSelfAnnotation},
|
| + {"monitor-self-argument",
|
| + required_argument,
|
| + nullptr,
|
| + kOptionMonitorSelfArgument},
|
| {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
|
| {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
|
| +#if defined(OS_WIN)
|
| + {"pipe-name", required_argument, nullptr, kOptionPipeName},
|
| +#endif // OS_WIN
|
| #if defined(OS_MACOSX)
|
| {"reset-own-crash-exception-port-to-system-default",
|
| no_argument,
|
| nullptr,
|
| kOptionResetOwnCrashExceptionPortToSystemDefault},
|
| -#elif defined(OS_WIN)
|
| - {"pipe-name", required_argument, nullptr, kOptionPipeName},
|
| #endif // OS_MACOSX
|
| {"url", required_argument, nullptr, kOptionURL},
|
| {"help", no_argument, nullptr, kOptionHelp},
|
| @@ -361,25 +471,25 @@ int HandlerMain(int argc, char* argv[]) {
|
| {nullptr, 0, nullptr, 0},
|
| };
|
|
|
| + Options options = {};
|
| +#if defined(OS_MACOSX)
|
| + options.handshake_fd = -1;
|
| +#endif
|
| + options.rate_limit = true;
|
| + options.upload_gzip = true;
|
| +
|
| int opt;
|
| while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
| switch (opt) {
|
| case kOptionAnnotation: {
|
| - std::string key;
|
| - std::string value;
|
| - if (!SplitStringFirst(optarg, '=', &key, &value)) {
|
| - ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
|
| + if (!AddKeyValueToMap(&options.annotations, optarg, "--annotation")) {
|
| return ExitFailure();
|
| }
|
| - std::string old_value;
|
| - if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
|
| - LOG(WARNING) << "duplicate key " << key << ", discarding value "
|
| - << old_value;
|
| - }
|
| break;
|
| }
|
| case kOptionDatabase: {
|
| - options.database = optarg;
|
| + options.database = base::FilePath(
|
| + ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
|
| break;
|
| }
|
| #if defined(OS_MACOSX)
|
| @@ -396,7 +506,8 @@ int HandlerMain(int argc, char* argv[]) {
|
| options.mach_service = optarg;
|
| break;
|
| }
|
| -#elif defined(OS_WIN)
|
| +#endif // OS_MACOSX
|
| +#if defined(OS_WIN)
|
| case kOptionInitialClientData: {
|
| if (!options.initial_client_data.InitializeFromString(optarg)) {
|
| ToolSupport::UsageHint(
|
| @@ -405,9 +516,26 @@ int HandlerMain(int argc, char* argv[]) {
|
| }
|
| break;
|
| }
|
| -#endif // OS_MACOSX
|
| +#endif // OS_WIN
|
| case kOptionMetrics: {
|
| - options.metrics = optarg;
|
| + options.metrics_dir = base::FilePath(
|
| + ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
|
| + break;
|
| + }
|
| + case kOptionMonitorSelf: {
|
| + options.monitor_self = true;
|
| + break;
|
| + }
|
| + case kOptionMonitorSelfAnnotation: {
|
| + if (!AddKeyValueToMap(&options.monitor_self_annotations,
|
| + optarg,
|
| + "--monitor-self-annotation")) {
|
| + return ExitFailure();
|
| + }
|
| + break;
|
| + }
|
| + case kOptionMonitorSelfArgument: {
|
| + options.monitor_self_arguments.push_back(optarg);
|
| break;
|
| }
|
| case kOptionNoRateLimit: {
|
| @@ -418,16 +546,17 @@ int HandlerMain(int argc, char* argv[]) {
|
| options.upload_gzip = false;
|
| break;
|
| }
|
| +#if defined(OS_WIN)
|
| + case kOptionPipeName: {
|
| + options.pipe_name = optarg;
|
| + break;
|
| + }
|
| +#endif // OS_WIN
|
| #if defined(OS_MACOSX)
|
| case kOptionResetOwnCrashExceptionPortToSystemDefault: {
|
| options.reset_own_crash_exception_port_to_system_default = true;
|
| break;
|
| }
|
| -#elif defined(OS_WIN)
|
| - case kOptionPipeName: {
|
| - options.pipe_name = optarg;
|
| - break;
|
| - }
|
| #endif // OS_MACOSX
|
| case kOptionURL: {
|
| options.url = optarg;
|
| @@ -475,7 +604,7 @@ int HandlerMain(int argc, char* argv[]) {
|
| }
|
| #endif // OS_MACOSX
|
|
|
| - if (!options.database) {
|
| + if (options.database.empty()) {
|
| ToolSupport::UsageHint(me, "--database is required");
|
| return ExitFailure();
|
| }
|
| @@ -486,15 +615,41 @@ int HandlerMain(int argc, char* argv[]) {
|
| }
|
|
|
| #if defined(OS_MACOSX)
|
| + if (options.reset_own_crash_exception_port_to_system_default) {
|
| + CrashpadClient::UseSystemDefaultHandler();
|
| + }
|
| +#endif // OS_MACOSX
|
| +
|
| + if (options.monitor_self) {
|
| + MonitorSelf(options);
|
| + }
|
| +
|
| + if (!options.monitor_self_annotations.empty()) {
|
| + // Establish these annotations even if --monitor-self is not present, in
|
| + // case something such as generate_dump wants to try to access them later.
|
| + //
|
| + // If the handler is part of a multi-purpose executable, simple annotations
|
| + // may already be present for this module. If they are, use them.
|
| + CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
|
| + SimpleStringDictionary* module_annotations =
|
| + crashpad_info->simple_annotations();
|
| + if (!module_annotations) {
|
| + module_annotations = new SimpleStringDictionary();
|
| + crashpad_info->set_simple_annotations(module_annotations);
|
| + }
|
| +
|
| + for (const auto& iterator : options.monitor_self_annotations) {
|
| + module_annotations->SetKeyValue(iterator.first.c_str(),
|
| + iterator.second.c_str());
|
| + }
|
| + }
|
| +
|
| +#if defined(OS_MACOSX)
|
| if (options.mach_service.empty()) {
|
| // Don’t do this when being run by launchd. See launchd.plist(5).
|
| CloseStdinAndStdout();
|
| }
|
|
|
| - if (options.reset_own_crash_exception_port_to_system_default) {
|
| - CrashpadClient::UseSystemDefaultHandler();
|
| - }
|
| -
|
| base::mac::ScopedMachReceiveRight receive_right;
|
|
|
| if (options.handshake_fd >= 0) {
|
| @@ -543,13 +698,11 @@ int HandlerMain(int argc, char* argv[]) {
|
| #endif // OS_MACOSX
|
|
|
| base::GlobalHistogramAllocator* histogram_allocator = nullptr;
|
| - if (options.metrics) {
|
| - const base::FilePath metrics_dir(
|
| - ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics));
|
| + if (!options.metrics_dir.empty()) {
|
| static const char kMetricsName[] = "CrashpadMetrics";
|
| const size_t kMetricsFileSize = 1 << 20;
|
| if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
|
| - metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
|
| + options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
|
| histogram_allocator = base::GlobalHistogramAllocator::Get();
|
| histogram_allocator->CreateTrackingHistograms(kMetricsName);
|
| }
|
| @@ -557,9 +710,8 @@ int HandlerMain(int argc, char* argv[]) {
|
|
|
| Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);
|
|
|
| - std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize(
|
| - base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType(
|
| - options.database))));
|
| + std::unique_ptr<CrashReportDatabase> database(
|
| + CrashReportDatabase::Initialize(options.database));
|
| if (!database) {
|
| return ExitFailure();
|
| }
|
|
|