Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(310)

Unified Diff: third_party/crashpad/crashpad/handler/handler_main.cc

Issue 2804713002: Update Crashpad to b4095401639ebe2ad33169e5c1d994065cbff1b8 (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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();
}

Powered by Google App Engine
This is Rietveld 408576698