From 726ab2a6553954ac3ade3b4f14272c58e7f3c85a Mon Sep 17 00:00:00 2001 From: Tim Zheng Date: Mon, 19 Aug 2019 15:43:02 -0700 Subject: [PATCH] Integrate Crashpad with Chrome OS This CL adds modification to Crashpad to integrate Crashpad reporting for Chrome on Chrome OS. Design doc: go/cros-crashpad BUG=chromium:944123 Change-Id: I22e2f2a93f32c2dc149c9c011fa8134cf6d5b74f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1707369 Commit-Queue: Joshua Peraza Reviewed-by: Joshua Peraza --- client/crashpad_client.h | 10 + client/crashpad_client_linux.cc | 25 +++ handler/handler_main.cc | 11 +- .../linux/crash_report_exception_handler.cc | 172 +++++++++++++++++- .../linux/crash_report_exception_handler.h | 5 + handler/linux/exception_handler_server.cc | 4 +- handler/linux/exception_handler_server.h | 4 + .../linux/exception_handler_server_test.cc | 2 + minidump/minidump_file_writer.cc | 2 +- util/file/file_io.h | 13 ++ util/file/file_io_posix.cc | 15 ++ util/file/file_writer.cc | 17 ++ util/file/file_writer.h | 16 ++ util/linux/exception_handler_protocol.h | 4 + util/misc/metrics.h | 3 + 15 files changed, 293 insertions(+), 10 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 56d738b7..36c9d1f8 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -588,6 +588,16 @@ class CrashpadClient { static void UseSystemDefaultHandler(); #endif +#if defined(OS_CHROMEOS) + //! \brief Sets a timestamp on the signal handler to be passed on to + //! crashpad_handler and then eventually Chrome OS's crash_reporter. + //! + //! \note This method is used by clients that use `StartHandler()` to start + //! a handler and not by clients that use any other handler starting + //! methods. + static void SetCrashLoopBefore(uint64_t crash_loop_before_time); +#endif + private: #if defined(OS_MACOSX) base::mac::ScopedMachSendRight exception_port_; diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 2e2ec30a..eb210a28 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -301,11 +301,20 @@ class RequestCrashDumpHandler : public SignalHandler { ExceptionHandlerProtocol::ClientInformation info = {}; info.exception_information_address = FromPointerCast(&GetExceptionInfo()); +#if defined(OS_CHROMEOS) + info.crash_loop_before_time = crash_loop_before_time_; +#endif ExceptionHandlerClient client(sock_to_handler_.get(), true); client.RequestCrashDump(info); } +#if defined(OS_CHROMEOS) + void SetCrashLoopBefore(uint64_t crash_loop_before_time) { + crash_loop_before_time_ = crash_loop_before_time; + } +#endif + private: RequestCrashDumpHandler() = default; @@ -314,6 +323,14 @@ class RequestCrashDumpHandler : public SignalHandler { ScopedFileHandle sock_to_handler_; pid_t handler_pid_ = -1; +#if defined(OS_CHROMEOS) + // An optional UNIX timestamp passed to us from Chrome. + // This will pass to crashpad_handler and then to Chrome OS crash_reporter. + // This should really be a time_t, but it's basically an opaque value (we + // don't anything with it except pass it along). + uint64_t crash_loop_before_time_ = 0; +#endif + DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler); }; @@ -526,4 +543,12 @@ void CrashpadClient::SetFirstChanceExceptionHandler( SignalHandler::Get()->SetFirstChanceHandler(handler); } +#if defined(OS_CHROMEOS) +// static +void CrashpadClient::SetCrashLoopBefore(uint64_t crash_loop_before_time) { + auto request_crash_dump_handler = RequestCrashDumpHandler::Get(); + request_crash_dump_handler->SetCrashLoopBefore(crash_loop_before_time); +} +#endif + } // namespace crashpad diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 05a2e7b4..91e3436f 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -509,6 +509,12 @@ class ScopedStoppable { int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources) { +#if defined(OS_CHROMEOS) + if (freopen("/var/log/chrome/chrome", "a", stderr) == nullptr) { + PLOG(ERROR) << "Failed to redirect stderr to /var/log/chrome/chrome"; + } +#endif + InstallCrashHandler(); CallMetricsRecordNormalExit metrics_record_normal_exit; @@ -900,8 +906,9 @@ int HandlerMain(int argc, info.exception_information_address = options.exception_information_address; info.sanitization_information_address = options.sanitization_information_address; - return exception_handler.HandleException(getppid(), info) ? EXIT_SUCCESS - : ExitFailure(); + return exception_handler.HandleException(getppid(), geteuid(), info) + ? EXIT_SUCCESS + : ExitFailure(); } #endif // OS_LINUX || OS_ANDROID diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 875afec3..ebba899c 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -29,6 +29,105 @@ #include "util/misc/tri_state.h" #include "util/misc/uuid.h" +#if defined(OS_CHROMEOS) +#include "handler/minidump_to_upload_parameters.h" +#include "snapshot/minidump/process_snapshot_minidump.h" +#include "util/posix/double_fork_and_exec.h" + +namespace { +// Returns the process name for a pid. +const std::string GetProcessNameFromPid(pid_t pid) { + // Symlink to process binary is at /proc/###/exe. + std::string link_path = "/proc/" + std::to_string(pid) + "/exe"; + + constexpr int kMaxSize = 4096; + std::unique_ptr buf(new char[kMaxSize]); + ssize_t size = readlink(link_path.c_str(), buf.get(), kMaxSize); + std::string result; + if (size < 0) { + PLOG(ERROR) << "Failed to readlink " << link_path; + } else { + result.assign(buf.get(), size); + size_t last_slash_pos = result.rfind('/'); + if (last_slash_pos != std::string::npos) { + result = result.substr(last_slash_pos + 1); + } + } + return result; +} + +bool WriteAnnotationsAndMinidump( + const std::map& parameters, + crashpad::MinidumpFileWriter& minidump, + crashpad::FileWriter& file_writer) { + for (const auto& kv : parameters) { + if (kv.first.find(':') != std::string::npos) { + LOG(ERROR) << "Annotation key cannot have ':' in it " << kv.first; + return false; + } + if (!file_writer.Write(kv.first.c_str(), strlen(kv.first.c_str()))) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + size_t value_size = strlen(kv.second.c_str()); + std::string value_size_str = std::to_string(value_size); + if (!file_writer.Write(value_size_str.c_str(), value_size_str.size())) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + if (!file_writer.Write(kv.second.c_str(), strlen(kv.second.c_str()))) { + return false; + } + } + + static constexpr char kMinidumpName[] = + "upload_file_minidump\"; filename=\"dump\":"; + if (!file_writer.Write(kMinidumpName, sizeof(kMinidumpName) - 1)) { + return false; + } + crashpad::FileOffset dump_size_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_size_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump size start offset"; + return false; + } + static constexpr char kMinidumpLengthFilling[] = "00000000000000000000:"; + if (!file_writer.Write(kMinidumpLengthFilling, + sizeof(kMinidumpLengthFilling) - 1)) { + return false; + } + crashpad::FileOffset dump_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump start offset"; + return false; + } + if (!minidump.WriteEverything(&file_writer)) { + return false; + } + crashpad::FileOffset dump_end_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_end_offset < 0) { + LOG(ERROR) << "Failed to get minidump end offset"; + return false; + } + + size_t dump_data_size = dump_end_offset - dump_start_offset; + std::string dump_data_size_str = std::to_string(dump_data_size); + file_writer.Seek(dump_size_start_offset + strlen(kMinidumpLengthFilling) - 1 - + dump_data_size_str.size(), + SEEK_SET); + if (!file_writer.Write(dump_data_size_str.c_str(), + dump_data_size_str.size())) { + return false; + } + return true; +} + +} // namespace +#endif // defined(OS_CHROMEOS) + namespace crashpad { CrashReportExceptionHandler::CrashReportExceptionHandler( @@ -37,14 +136,18 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( const std::map* process_annotations, const UserStreamDataSources* user_stream_data_sources) : database_(database), +#if !defined(OS_CHROMEOS) upload_thread_(upload_thread), +#endif process_annotations_(process_annotations), - user_stream_data_sources_(user_stream_data_sources) {} + user_stream_data_sources_(user_stream_data_sources) { +} CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; bool CrashReportExceptionHandler::HandleException( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, @@ -60,6 +163,7 @@ bool CrashReportExceptionHandler::HandleException( return HandleExceptionWithConnection(&connection, info, + client_uid, requesting_thread_stack_address, requesting_thread_id, local_report_id); @@ -67,6 +171,7 @@ bool CrashReportExceptionHandler::HandleException( bool CrashReportExceptionHandler::HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id) { @@ -80,12 +185,13 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( } return HandleExceptionWithConnection( - &client, info, 0, nullptr, local_report_id); + &client, info, client_uid, 0, nullptr, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id) { @@ -131,6 +237,12 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( process_snapshot.AddAnnotation(p.first, p.second); } + UUID uuid; +#if defined(OS_CHROMEOS) + uuid.InitializeWithNew(); + process_snapshot.SetReportID(uuid); +#else + std::unique_ptr new_report; CrashReportDatabase::OperationStatus database_status = database_->PrepareNewCrashReport(&new_report); @@ -142,6 +254,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot.SetReportID(new_report->ReportID()); +#endif ProcessSnapshot* snapshot = nullptr; ProcessSnapshotSanitized sanitized; @@ -193,6 +306,53 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( minidump.InitializeFromSnapshot(snapshot); AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); +#if defined(OS_CHROMEOS) + FileWriter file_writer; + if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); + return false; + } + + std::map parameters = + BreakpadHTTPFormParametersFromMinidump(snapshot); + // Used to differenciate between breakpad and crashpad while the switch is + // ramping up. + parameters.emplace("crash_library", "crashpad"); + + if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); + return false; + } + + // CrOS uses crash_reporter instead of Crashpad to report crashes. + // crash_reporter needs to know the pid and uid of the crashing process. + std::vector argv({"/sbin/crash_reporter"}); + + argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); + argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); + argv.push_back("--uid=" + std::to_string(client_uid)); + std::string process_name = GetProcessNameFromPid(*requesting_thread_id); + argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); + + if (info.crash_loop_before_time != 0) { + argv.push_back("--crash_loop_before=" + + std::to_string(info.crash_loop_before_time)); + } + + if (!DoubleForkAndExec(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { + LOG(ERROR) << "DoubleForkAndExec failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return false; + } + +#else + if (!minidump.WriteEverything(new_report->Writer())) { LOG(ERROR) << "WriteEverything failed"; Metrics::ExceptionCaptureResult( @@ -200,7 +360,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } - UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); if (database_status != CrashReportDatabase::kNoError) { @@ -209,13 +368,14 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return false; } - if (local_report_id != nullptr) { - *local_report_id = uuid; - } if (upload_thread_) { upload_thread_->ReportPending(uuid); } +#endif + if (local_report_id != nullptr) { + *local_report_id = uuid; + } } Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index dba8b63a..ca527587 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -65,6 +65,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { // ExceptionHandlerServer::Delegate: bool HandleException(pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address = 0, pid_t* requesting_thread_id = nullptr, @@ -72,6 +73,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) override; @@ -80,12 +82,15 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithConnection( PtraceConnection* connection, const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak +#if !defined(OS_CHROMEOS) CrashReportUploadThread* upload_thread_; // weak +#endif const std::map* process_annotations_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index ef03696a..7bb14f92 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -448,6 +448,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( bool multiple_clients) { pid_t client_process_id = creds.pid; pid_t requesting_thread_id = -1; + uid_t client_uid = creds.uid; switch ( strategy_decider_->ChooseStrategy(client_sock, multiple_clients, creds)) { @@ -469,6 +470,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( case PtraceStrategyDecider::Strategy::kDirectPtrace: { delegate_->HandleException(client_process_id, + client_uid, client_info, requesting_thread_stack_address, &requesting_thread_id); @@ -482,7 +484,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( case PtraceStrategyDecider::Strategy::kUseBroker: DCHECK(!multiple_clients); delegate_->HandleExceptionWithBroker( - client_process_id, client_info, client_sock); + client_process_id, client_uid, client_info, client_sock); break; } diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index b6251e14..48dcf07b 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -76,6 +76,7 @@ class ExceptionHandlerServer { //! \brief Called on receipt of a crash dump request from a client. //! //! \param[in] client_process_id The process ID of the crashing client. + //! \param[in] client_uid The user ID of the crashing client. //! \param[in] info Information on the client. //! \param[in] requesting_thread_stack_address Any address within the stack //! range for the the thread that sent the crash dump request. Optional. @@ -88,6 +89,7 @@ class ExceptionHandlerServer { //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleException( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address = 0, pid_t* requesting_thread_id = nullptr, @@ -97,6 +99,7 @@ class ExceptionHandlerServer { //! crash that should be mediated by a PtraceBroker. //! //! \param[in] client_process_id The process ID of the crashing client. + //! \param[in] client_uid The uid of the crashing client. //! \param[in] info Information on the client. //! \param[in] broker_sock A socket connected to the PtraceBroker. //! \param[out] local_report_id The unique identifier for the report created @@ -104,6 +107,7 @@ class ExceptionHandlerServer { //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) = 0; diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index ea10db35..45f19965 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -108,6 +108,7 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { } bool HandleException(pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id = nullptr, @@ -141,6 +142,7 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) override { diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 72265453..f29a6fae 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -232,7 +232,7 @@ bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { // it as a valid minidump file. header_.Signature = MINIDUMP_SIGNATURE; - if (file_writer->Seek(start_offset, SEEK_SET) != 0) { + if (file_writer->Seek(start_offset, SEEK_SET) < 0) { return false; } diff --git a/util/file/file_io.h b/util/file/file_io.h index 797db682..7af47f85 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -398,6 +398,19 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions); +#if defined(OS_CHROMEOS) +//! \brief Wraps memfd_create(), logging an error if the operation fails. +//! Unlike other file open operations, this doesn't set `O_CLOEXEC`. +//! +//! \return The newly opened FileHandle, or an invalid FileHandle on failure. +//! +//! \sa ScopedFileHandle +//! \sa LoggingOpenFileForRead +//! \sa LoggingOpenFileForWrite +//! \sa LoggingOpenFileForReadAndWrite +FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path); +#endif + //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation //! fails. //! diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index f3116169..03fc262e 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -98,6 +99,12 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, permissions == FilePermissions::kWorldReadable ? 0644 : 0600)); } +#if defined(OS_CHROMEOS) +FileHandle OpenMemFileForOutput(const base::FilePath& path) { + return HANDLE_EINTR(memfd_create(path.value().c_str(), 0)); +} +#endif + } // namespace namespace internal { @@ -149,6 +156,14 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, return fd; } +#if defined(OS_CHROMEOS) +FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path) { + FileHandle fd = OpenMemFileForOutput(path); + PLOG_IF(ERROR, fd < 0) << "memfd_create " << path.value(); + return fd; +} +#endif + FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions) { diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index 13ac6cf5..5f922429 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -171,6 +171,23 @@ bool FileWriter::Open(const base::FilePath& path, return true; } +#if defined(OS_CHROMEOS) +bool FileWriter::OpenMemfd(const base::FilePath& path) { + CHECK(!file_.is_valid()); + file_.reset(LoggingOpenMemFileForWrite(path)); + if (!file_.is_valid()) { + return false; + } + + weak_file_handle_file_writer_.set_file_handle(file_.get()); + return true; +} + +int FileWriter::fd() { + return file_.get(); +} +#endif + void FileWriter::Close() { CHECK(file_.is_valid()); diff --git a/util/file/file_writer.h b/util/file/file_writer.h index ed261ec5..1f9a0203 100644 --- a/util/file/file_writer.h +++ b/util/file/file_writer.h @@ -131,6 +131,22 @@ class FileWriter : public FileWriterInterface { FileWriteMode write_mode, FilePermissions permissions); +#if defined(OS_CHROMEOS) + //! \brief Wraps LoggingOpenMemFileForWrite(). + //! + //! \return `true` if the operation succeeded, `false` if it failed, with an + //! error message logged. + //! + //! \note After a successful call, this method or Open() cannot be called + // again until after Close(). + bool OpenMemfd(const base::FilePath& path); + + //! \brief Returns the underlying file descriptor. + //! + //! \note This is used when this writes to a Memfd. + int fd(); +#endif + //! \brief Wraps CheckedCloseHandle(). //! //! \note It is only valid to call this method on an object that has had a diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 7f4da266..85b2f23f 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -50,6 +50,10 @@ class ExceptionHandlerProtocol { //! \brief The address in the client's address space of a //! SanitizationInformation struct, or 0 if there is no such struct. VMAddress sanitization_information_address; + +#if defined(OS_CHROMEOS) + uint64_t crash_loop_before_time; +#endif }; //! \brief The signal used to indicate a crash dump is complete. diff --git a/util/misc/metrics.h b/util/misc/metrics.h index 8046497e..d9763812 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -139,6 +139,9 @@ class Metrics { //! \brief Sanitization caused this crash dump to be skipped. kSkippedDueToSanitization = 11, + //! \brief Failure to open a memfd caused this crash dump to be skipped. + kOpenMemfdFailed = 12, + //! \brief The number of values in this enumeration; not a valid value. kMaxValue };