From ce93b696b66372ef98fc339c1c5a75f281d2a421 Mon Sep 17 00:00:00 2001 From: Anton Ovchinnikov Date: Mon, 4 Mar 2019 13:13:06 +0100 Subject: [PATCH 001/478] chore: Add Makefile with helpers --- Makefile | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..b741664b24 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +SHELL := /bin/bash +PATH := $(PWD)/../depot_tools:$(PATH) + +all: + echo 'Nothing to do' && exit 1 + +build: + gn gen out/Default + ninja -C out/Default +.PHONY: build + +update: + gclient sync + +example: + g++ -g \ + -o example example.cpp \ + -I. -I./third_party/mini_chromium/mini_chromium \ + -std=c++14 \ + -L./out/Default/obj/client -lclient \ + -L./out/Default/obj/util -lutil \ + -L./out/Default/obj/third_party/mini_chromium/mini_chromium/base -lbase \ + -framework Foundation -framework Security -framework CoreText \ + -framework CoreGraphics -framework IOKit -lbsm +.PHONY: example From d751bd057f9dd39d0349a4d5583fbad0296ef7e5 Mon Sep 17 00:00:00 2001 From: Anton Ovchinnikov Date: Mon, 4 Mar 2019 16:31:35 +0100 Subject: [PATCH 002/478] feat: Add attachments support to crashpad handler --- README.md | 6 +++++ client/crashpad_client.h | 13 +++++++++++ handler/handler_main.cc | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/README.md b/README.md index b20777bbf8..0798f000bb 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,9 @@ https://chromium.googlesource.com/crashpad/crashpad. perform automated builds and tests. * [crashpad-dev](https://groups.google.com/a/chromium.org/group/crashpad-dev) is the Crashpad developers’ mailing list. + +## Sentry modifications + +File attachments support for MacOS and Windows. + +Based on changes made in https://github.com/Youw/crashpad/, distributed with Apache 2.0 License. diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 8bf43acdaa..3275d58dc2 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -112,6 +112,19 @@ class CrashpadClient { bool restartable, bool asynchronous_start); +#if defined(OS_MACOSX) + bool StartHandlerWithAttachments( + const base::FilePath& handler, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map& annotations, + const std::map& fileAttachments, + const std::vector& arguments, + bool restartable, + bool asynchronous_start); +#endif + #if defined(OS_ANDROID) || DOXYGEN //! \brief Installs a signal handler to execute `/system/bin/app_process` and //! load a Java class in response to a crash. diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 31686b3eb8..6d7850b945 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -149,6 +149,9 @@ void Usage(const base::FilePath& me) { #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" +#if defined(OS_WIN) || defined(OS_MACOSX) +" --attachment=NAME=PATH attach a copy of a file, along with a crash dump\n" +#endif // OS_WIN || OS_MACOSX " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); @@ -158,6 +161,7 @@ void Usage(const base::FilePath& me) { struct Options { std::map annotations; std::map monitor_self_annotations; + std::map attachments; std::string url; base::FilePath database; base::FilePath metrics_dir; @@ -204,6 +208,33 @@ bool AddKeyValueToMap(std::map* map, return true; } +#if defined(OS_WIN) || defined(OS_MACOSX) +// Overloaded version, to accept base::FilePath as a VALUE. +bool AddKeyValueToMap(std::map* map, + const std::string& key_value, + const char* argument) { + std::string key; + std::string raw_value; + if (!SplitStringFirst(key_value, '=', &key, &raw_value)) { + LOG(ERROR) << argument << " requires NAME=PATH"; + return false; + } + +#ifdef OS_WIN + base::FilePath value(base::UTF8ToUTF16(raw_value)); +#else + base::FilePath value(raw_value); +#endif + + base::FilePath old_value; + if (!MapInsertOrReplace(map, key, value, &old_value)) { + LOG(WARNING) << argument << " has duplicate name " << key + << ", discarding value " << old_value.value().c_str(); + } + return true; +} +#endif // OS_WIN || OS_MACOSX + // 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 @@ -553,6 +584,9 @@ int HandlerMain(int argc, kOptionSanitizationInformation, #endif kOptionURL, +#if defined(OS_WIN) || defined(OS_MACOSX) + kOptionAttachment, +#endif // OS_WIN || OS_MACOSX // Standard options. kOptionHelp = -2, @@ -612,6 +646,9 @@ int HandlerMain(int argc, kOptionSanitizationInformation}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, +#if defined(OS_WIN) || defined(OS_MACOSX) + {"attachment", required_argument, nullptr, kOptionAttachment}, +#endif // OS_WIN || O_MACOSX {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, {nullptr, 0, nullptr, 0}, @@ -749,6 +786,14 @@ int HandlerMain(int argc, options.url = optarg; break; } +#if defined(OS_WIN) || defined(OS_MACOSX) + case kOptionAttachment: { + if (!AddKeyValueToMap(&options.attachments, optarg, "--attachment")) { + return ExitFailure(); + } + break; + } +#endif // OS_WIN || OS_MACOSX case kOptionHelp: { Usage(me); MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); @@ -875,6 +920,8 @@ int HandlerMain(int argc, #if defined(OS_FUCHSIA) // TODO(scottmg): Process level file attachments, and for all platforms. nullptr, +#elif defined(OS_WIN) || defined(OS_MACOSX) + &options.attachments, #endif user_stream_sources); From 9a7219a27e9d09facb65a338f96e408a6004769f Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Tue, 27 Nov 2018 01:31:49 +0200 Subject: [PATCH 003/478] Add attachments support to macOS crash report database --- client/crash_report_database.cc | 2 +- client/crash_report_database.h | 4 +- client/crash_report_database_mac.mm | 147 +++++++++++++++++- handler/handler_main.cc | 3 - .../linux/crash_report_exception_handler.cc | 20 +++ .../linux/crash_report_exception_handler.h | 7 + handler/mac/crash_report_exception_handler.cc | 20 +++ handler/mac/crash_report_exception_handler.h | 7 + 8 files changed, 198 insertions(+), 12 deletions(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index d300a8f9ca..b1d0eaf6fe 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -78,7 +78,7 @@ CrashReportDatabase::UploadReport::~UploadReport() { } } -bool CrashReportDatabase::UploadReport::Initialize(const base::FilePath path, +bool CrashReportDatabase::UploadReport::Initialize(const base::FilePath& path, CrashReportDatabase* db) { database_ = db; InitializeAttachments(); diff --git a/client/crash_report_database.h b/client/crash_report_database.h index 1d6a9ed03a..ebd1dc7304 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -117,8 +117,6 @@ class CrashReportDatabase { //! \brief Adds an attachment to the report. //! - //! \note This function is not yet implemented on macOS or Windows. - //! //! \param[in] name The key and name for the attachment, which will be //! included in the http upload. The attachment will not appear in the //! minidump report. \a name should only use characters from the set @@ -171,7 +169,7 @@ class CrashReportDatabase { friend class CrashReportDatabaseMac; friend class CrashReportDatabaseWin; - bool Initialize(const base::FilePath path, CrashReportDatabase* database); + bool Initialize(const base::FilePath& path, CrashReportDatabase* database); void InitializeAttachments(); std::unique_ptr reader_; diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 414dd5a4a4..75a09264fb 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -34,7 +34,9 @@ #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "client/settings.h" +#include "util/file/directory_reader.h" #include "util/file/file_io.h" +#include "util/file/filesystem.h" #include "util/mac/xattr.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/metrics.h" @@ -46,6 +48,7 @@ constexpr char kWriteDirectory[] = "new"; constexpr char kUploadPendingDirectory[] = "pending"; constexpr char kCompletedDirectory[] = "completed"; +constexpr char kAttachmentsDirectory[] = "attachments"; constexpr char kSettings[] = "settings.dat"; @@ -148,6 +151,10 @@ OperationStatus SkipReportUpload(const UUID& uuid, Metrics::CrashSkippedReason reason) override; OperationStatus DeleteReport(const UUID& uuid) override; OperationStatus RequestUpload(const UUID& uuid) override; + int CleanDatabase(time_t lockfile_ttl) override; + + // Build a filepath for the directory for the report to hold attachments. + base::FilePath AttachmentsPath(const UUID& uuid); private: // CrashReportDatabase: @@ -239,6 +246,16 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, const base::FilePath& report_path, base::FilePath* out_path); + //! \brief Cleans any attachments that have no associated report. + void CleanOrphanedAttachments(); + + //! \brief Attempt to remove any attachments associated with the given + //! report UUID. + //! There may not be any, so failing is not an error. + //! + //! \param[in] uuid The report identifier which attachments to remove. + void RemoveAttachmentsByUUID(const UUID& uuid); + base::FilePath base_dir_; Settings settings_; bool xattr_new_names_; @@ -249,12 +266,55 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, FileWriter* CrashReportDatabase::NewReport::AddAttachment( const std::string& name) { - // Attachments aren't implemented in the Mac database yet. - return nullptr; + if (!AttachmentNameIsOK(name)) { + LOG(ERROR) << "invalid name for attachment " << name; + return nullptr; + } + + base::FilePath attachments_dir = + static_cast(database_)->AttachmentsPath( + uuid_); + if (!LoggingCreateDirectory( + attachments_dir, FilePermissions::kOwnerOnly, true)) { + return nullptr; + } + + base::FilePath path = attachments_dir.Append(name); + + auto writer = std::make_unique(); + if (!writer->Open( + path, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly)) { + LOG(ERROR) << "could not open " << path.value(); + return nullptr; + } + attachment_writers_.emplace_back(std::move(writer)); + attachment_removers_.emplace_back(ScopedRemoveFile(path)); + return attachment_writers_.back().get(); } void CrashReportDatabase::UploadReport::InitializeAttachments() { - // Attachments aren't implemented in the Mac database yet. + base::FilePath attachments_dir = + static_cast(database_)->AttachmentsPath( + uuid); + DirectoryReader reader; + if (!reader.Open(attachments_dir)) { + return; + } + + base::FilePath filename; + DirectoryReader::Result dir_result; + while ((dir_result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath filepath(attachments_dir.Append(filename)); + std::unique_ptr reader(std::make_unique()); + if (!reader->Open(filepath)) { + LOG(ERROR) << "attachment " << filepath.value() + << " couldn't be opened, skipping"; + continue; + } + attachment_readers_.emplace_back(std::move(reader)); + attachment_map_[filename.value()] = attachment_readers_.back().get(); + } } CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) @@ -285,6 +345,9 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return false; } + if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kAttachmentsDirectory))) + return false; + if (!settings_.Initialize(base_dir_.Append(kSettings))) return false; @@ -378,6 +441,14 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, } ignore_result(report->file_remover_.release()); + // Close all the attachments and disarm their removers too. + for (auto& writer : report->attachment_writers_) { + writer->Close(); + } + for (auto& remover : report->attachment_removers_) { + ignore_result(remover.release()); + } + Metrics::CrashReportPending(Metrics::PendingReportReason::kNewlyCreated); Metrics::CrashReportSize(size); @@ -441,11 +512,10 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, if (!ReadReportMetadataLocked(upload_report->file_path, upload_report.get())) return kDatabaseError; - if (!upload_report->reader_->Open(upload_report->file_path)) { + if (!upload_report->Initialize(upload_report->file_path, this)) { return kFileSystemError; } - upload_report->database_ = this; upload_report->lock_fd.reset(lock.release()); upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); @@ -541,6 +611,8 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return kFileSystemError; } + RemoveAttachmentsByUUID(uuid); + return kNoError; } @@ -625,6 +697,22 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return kNoError; } +int CrashReportDatabaseMac::CleanDatabase(time_t lockfile_ttl) { + (void)lockfile_ttl; + CleanOrphanedAttachments(); + return 0; +} + +base::FilePath CrashReportDatabaseMac::AttachmentsPath(const UUID& uuid) { +#if defined(OS_WIN) + const std::wstring uuid_string = uuid.ToString16(); +#else + const std::string uuid_string = uuid.ToString(); +#endif + + return base_dir_.Append(kAttachmentsDirectory).Append(uuid_string); +} + // static base::ScopedFD CrashReportDatabaseMac::ObtainReportLock( const base::FilePath& path) { @@ -747,6 +835,55 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return kNoError; } +void CrashReportDatabaseMac::CleanOrphanedAttachments() { + base::FilePath root_attachments_dir(base_dir_.Append(kAttachmentsDirectory)); + DirectoryReader reader; + if (!reader.Open(root_attachments_dir)) { + LOG(ERROR) << "no attachments dir"; + return; + } + + base::FilePath filename; + DirectoryReader::Result result; + while ((result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath path(root_attachments_dir.Append(filename)); + if (IsDirectory(path, false)) { + UUID uuid; + if (!uuid.InitializeFromString(filename.value())) { + LOG(ERROR) << "unexpected attachment dir name " << filename.value(); + continue; + } + + base::FilePath report_path = LocateCrashReport(uuid, kReportStateAny); + if (!report_path.empty()) { + continue; + } + + // Couldn't find a report, assume these attachments are orphaned. + RemoveAttachmentsByUUID(uuid); + } + } +} + +void CrashReportDatabaseMac::RemoveAttachmentsByUUID(const UUID &uuid) { + base::FilePath attachments_dir = AttachmentsPath(uuid); + DirectoryReader reader; + if (!reader.Open(attachments_dir)) { + return; + } + + base::FilePath filename; + DirectoryReader::Result result; + while ((result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath filepath(attachments_dir.Append(filename)); + LoggingRemoveFile(filepath); + } + + LoggingRemoveDirectory(attachments_dir); +} + std::unique_ptr InitializeInternal( const base::FilePath& path, bool may_create) { diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 6d7850b945..b223c9095e 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -207,8 +207,6 @@ bool AddKeyValueToMap(std::map* map, } return true; } - -#if defined(OS_WIN) || defined(OS_MACOSX) // Overloaded version, to accept base::FilePath as a VALUE. bool AddKeyValueToMap(std::map* map, const std::string& key_value, @@ -233,7 +231,6 @@ bool AddKeyValueToMap(std::map* map, } return true; } -#endif // OS_WIN || OS_MACOSX // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is // to prevent multiple exit events from inadvertently being recorded, which diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 71a7009b64..2c8fbe82bd 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -35,10 +35,12 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources) : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), + process_attachments_(process_attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; @@ -173,6 +175,24 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } + if (process_attachments_) { + // Note that attachments are read at this point each time rather than once + // so that if the contents of the file has changed it will be re-read for + // each upload (e.g. in the case of a log file). + for (const auto& it : *process_attachments_) { + FileWriter* writer = new_report->AddAttachment(it.first); + if (writer) { + std::string contents; + if (!LoggingReadEntireFile(it.second, &contents)) { + // Not being able to read the file isn't considered fatal, and + // should not prevent the report from being processed. + continue; + } + writer->Write(contents.data(), contents.size()); + } + } + } + UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 9951d840dc..1be7015f9f 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -18,6 +18,7 @@ #include #include +#include "base/files/file_path.h" #include "base/macros.h" #include "client/crash_report_database.h" #include "handler/crash_report_upload_thread.h" @@ -50,6 +51,10 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { //! To interoperate with Breakpad servers, the recommended practice is to //! specify values for the `"prod"` and `"ver"` keys as process //! annotations. + //! \param[in] process_attachments A map of file name keys to file paths to be + //! included in the report. Each time a report is written, the file paths + //! will be read in their entirety and included in the report using the + //! file name key as the name in the http upload. //! \param[in] user_stream_data_sources Data sources to be used to extend //! crash reports. For each crash report that is written, the data sources //! are called in turn. These data sources may contribute additional @@ -58,6 +63,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources); ~CrashReportExceptionHandler(); @@ -81,6 +87,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map* process_annotations_; // weak + const std::map* process_attachments_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); diff --git a/handler/mac/crash_report_exception_handler.cc b/handler/mac/crash_report_exception_handler.cc index 9919e9557b..cdceceb644 100644 --- a/handler/mac/crash_report_exception_handler.cc +++ b/handler/mac/crash_report_exception_handler.cc @@ -45,10 +45,12 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources) : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), + process_attachments_(process_attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() { @@ -178,6 +180,24 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( return KERN_FAILURE; } + if (process_attachments_) { + // Note that attachments are read at this point each time rather than once + // so that if the contents of the file has changed it will be re-read for + // each upload (e.g. in the case of a log file). + for (const auto& it : *process_attachments_) { + FileWriter* writer = new_report->AddAttachment(it.first); + if (writer) { + std::string contents; + if (!LoggingReadEntireFile(it.second, &contents)) { + // Not being able to read the file isn't considered fatal, and + // should not prevent the report from being processed. + continue; + } + writer->Write(contents.data(), contents.size()); + } + } + } + UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); diff --git a/handler/mac/crash_report_exception_handler.h b/handler/mac/crash_report_exception_handler.h index 0b44de67b7..a9a9dc71a9 100644 --- a/handler/mac/crash_report_exception_handler.h +++ b/handler/mac/crash_report_exception_handler.h @@ -20,6 +20,7 @@ #include #include +#include "base/files/file_path.h" #include "base/macros.h" #include "client/crash_report_database.h" #include "handler/crash_report_upload_thread.h" @@ -48,6 +49,10 @@ class CrashReportExceptionHandler : public UniversalMachExcServer::Interface { //! To interoperate with Breakpad servers, the recommended practice is to //! specify values for the `"prod"` and `"ver"` keys as process //! annotations. + //! \param[in] process_attachments A map of file name keys to file paths to be + //! included in the report. Each time a report is written, the file paths + //! will be read in their entirety and included in the report using the + //! file name key as the name in the http upload. //! \param[in] user_stream_data_sources Data sources to be used to extend //! crash reports. For each crash report that is written, the data sources //! are called in turn. These data sources may contribute additional @@ -56,6 +61,7 @@ class CrashReportExceptionHandler : public UniversalMachExcServer::Interface { CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources); ~CrashReportExceptionHandler(); @@ -84,6 +90,7 @@ class CrashReportExceptionHandler : public UniversalMachExcServer::Interface { CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map* process_annotations_; // weak + const std::map* process_attachments_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); From a9419f2fb1c426f49a0b2b45ae1c2652e0aaadd3 Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Sat, 7 Jul 2018 00:37:29 +0300 Subject: [PATCH 004/478] Add attachments support to Windows crash report database --- client/crash_report_database.cc | 8 + client/crash_report_database.h | 2 + client/crash_report_database_generic.cc | 8 - client/crash_report_database_win.cc | 147 +++++++++++++++++- handler/win/crash_report_exception_handler.cc | 20 +++ handler/win/crash_report_exception_handler.h | 7 + 6 files changed, 181 insertions(+), 11 deletions(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index b1d0eaf6fe..0bbee5f267 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -19,6 +19,14 @@ namespace crashpad { +bool CrashReportDatabase::AttachmentNameIsOK(const std::string& name) { + for (const char c : name) { + if (c != '_' && c != '-' && c != '.' && !isalnum(c)) + return false; + } + return true; +} + CrashReportDatabase::Report::Report() : uuid(), file_path(), diff --git a/client/crash_report_database.h b/client/crash_report_database.h index ebd1dc7304..ef181a7c55 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -395,6 +395,8 @@ class CrashReportDatabase { protected: CrashReportDatabase() {} + static bool AttachmentNameIsOK(const std::string& name); + private: //! \brief Adjusts a crash report record’s metadata to account for an upload //! attempt, and updates the last upload attempt time as returned by diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index 8e93237421..f4c3fbf646 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -42,14 +42,6 @@ UUID UUIDFromReportPath(const base::FilePath& path) { return uuid; } -bool AttachmentNameIsOK(const std::string& name) { - for (const char c : name) { - if (c != '_' && c != '-' && c != '.' && !isalnum(c)) - return false; - } - return true; -} - using OperationStatus = CrashReportDatabase::OperationStatus; constexpr base::FilePath::CharType kSettings[] = diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 8967770676..af2c0a8240 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -29,6 +29,8 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "client/settings.h" +#include "util/file/directory_reader.h" +#include "util/file/filesystem.h" #include "util/misc/implicit_cast.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/metrics.h" @@ -39,6 +41,7 @@ namespace { constexpr wchar_t kReportsDirectory[] = L"reports"; constexpr wchar_t kMetadataFileName[] = L"metadata"; +constexpr wchar_t kAttachmentsDirectory[] = L"attachments"; constexpr wchar_t kSettings[] = L"settings.dat"; @@ -600,6 +603,10 @@ class CrashReportDatabaseWin : public CrashReportDatabase { Metrics::CrashSkippedReason reason) override; OperationStatus DeleteReport(const UUID& uuid) override; OperationStatus RequestUpload(const UUID& uuid) override; + int CleanDatabase(time_t lockfile_ttl) override; + + // Build a filepath for the directory for the report to hold attachments. + base::FilePath AttachmentsPath(const UUID& uuid); private: // CrashReportDatabase: @@ -609,6 +616,16 @@ class CrashReportDatabaseWin : public CrashReportDatabase { std::unique_ptr AcquireMetadata(); + //! \brief Cleans any attachments that have no associated report. + void CleanOrphanedAttachments(); + + //! \brief Attempt to remove any attachments associated with the given + //! report UUID. + //! There may not be any, so failing is not an error. + //! + //! \param[in] uuid The report identifier which attachments to remove. + void RemoveAttachmentsByUUID(const UUID& uuid); + base::FilePath base_dir_; Settings settings_; InitializationStateDcheck initialized_; @@ -618,12 +635,56 @@ class CrashReportDatabaseWin : public CrashReportDatabase { FileWriter* CrashReportDatabase::NewReport::AddAttachment( const std::string& name) { - // Attachments aren't implemented in the Windows database yet. - return nullptr; + if (!AttachmentNameIsOK(name)) { + LOG(ERROR) << "invalid name for attachment " << name; + return nullptr; + } + + base::FilePath attachments_dir = + static_cast(database_)->AttachmentsPath( + uuid_); + if (!LoggingCreateDirectory( + attachments_dir, FilePermissions::kOwnerOnly, true)) { + return nullptr; + } + + base::FilePath path = attachments_dir.Append(base::UTF8ToUTF16(name)); + + auto writer = std::make_unique(); + if (!writer->Open( + path, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly)) { + LOG(ERROR) << "could not open " << base::UTF16ToUTF8(path.value()); + return nullptr; + } + attachment_writers_.emplace_back(std::move(writer)); + attachment_removers_.emplace_back(ScopedRemoveFile(path)); + return attachment_writers_.back().get(); } void CrashReportDatabase::UploadReport::InitializeAttachments() { - // Attachments aren't implemented in the Windows database yet. + base::FilePath attachments_dir = + static_cast(database_)->AttachmentsPath( + uuid); + DirectoryReader reader; + if (!reader.Open(attachments_dir)) { + return; + } + + base::FilePath filename; + DirectoryReader::Result dir_result; + while ((dir_result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath filepath(attachments_dir.Append(filename)); + std::unique_ptr reader(std::make_unique()); + if (!reader->Open(filepath)) { + LOG(ERROR) << "attachment " << base::UTF16ToUTF8(filepath.value()) + << " couldn't be opened, skipping"; + continue; + } + attachment_readers_.emplace_back(std::move(reader)); + attachment_map_[base::UTF16ToUTF8(filename.value())] = + attachment_readers_.back().get(); + } } CrashReportDatabaseWin::CrashReportDatabaseWin(const base::FilePath& path) @@ -647,6 +708,9 @@ bool CrashReportDatabaseWin::Initialize(bool may_create) { if (!CreateDirectoryIfNecessary(base_dir_.Append(kReportsDirectory))) return false; + if (!CreateDirectoryIfNecessary(base_dir_.Append(kAttachmentsDirectory))) + return false; + if (!settings_.Initialize(base_dir_.Append(kSettings))) return false; @@ -689,6 +753,14 @@ OperationStatus CrashReportDatabaseWin::FinishedWritingCrashReport( ignore_result(report->file_remover_.release()); + // Close all the attachments and disarm their removers too. + for (auto& writer : report->attachment_writers_) { + writer->Close(); + } + for (auto& remover : report->attachment_removers_) { + ignore_result(remover.release()); + } + *uuid = report->ReportID(); Metrics::CrashReportPending(Metrics::PendingReportReason::kNewlyCreated); @@ -815,6 +887,9 @@ OperationStatus CrashReportDatabaseWin::DeleteReport(const UUID& uuid) { << base::UTF16ToUTF8(report_path.value()); return kFileSystemError; } + + RemoveAttachmentsByUUID(uuid); + return kNoError; } @@ -843,6 +918,62 @@ std::unique_ptr CrashReportDatabaseWin::AcquireMetadata() { return Metadata::Create(metadata_file, base_dir_.Append(kReportsDirectory)); } +void CrashReportDatabaseWin::CleanOrphanedAttachments() { + base::FilePath root_attachments_dir(base_dir_.Append(kAttachmentsDirectory)); + DirectoryReader reader; + if (!reader.Open(root_attachments_dir)) { + LOG(ERROR) << "no attachments dir"; + return; + } + + std::unique_ptr metadata(AcquireMetadata()); + if (!metadata) + return; + + base::FilePath filename; + DirectoryReader::Result result; + while ((result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath path(root_attachments_dir.Append(filename)); + if (IsDirectory(path, false)) { + UUID uuid; + if (!uuid.InitializeFromString(filename.value())) { + LOG(ERROR) << "unexpected attachment dir name " + << base::UTF16ToUTF8(filename.value()); + continue; + } + + // Check to see if the report exist. + const ReportDisk* report_disk; + const OperationStatus os = metadata->FindSingleReport(uuid, &report_disk); + if (os != OperationStatus::kReportNotFound) { + continue; + } + + // Couldn't find a report, assume these attachments are orphaned. + RemoveAttachmentsByUUID(uuid); + } + } +} + +void CrashReportDatabaseWin::RemoveAttachmentsByUUID(const UUID &uuid) { + base::FilePath attachments_dir = AttachmentsPath(uuid); + DirectoryReader reader; + if (!reader.Open(attachments_dir)) { + return; + } + + base::FilePath filename; + DirectoryReader::Result result; + while ((result = reader.NextFile(&filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath filepath(attachments_dir.Append(filename)); + LoggingRemoveFile(filepath); + } + + LoggingRemoveDirectory(attachments_dir); +} + std::unique_ptr InitializeInternal( const base::FilePath& path, bool may_create) { @@ -886,6 +1017,16 @@ OperationStatus CrashReportDatabaseWin::RequestUpload(const UUID& uuid) { return kNoError; } +int CrashReportDatabaseWin::CleanDatabase(time_t lockfile_ttl) { + (void)lockfile_ttl; + CleanOrphanedAttachments(); + return 0; +} + +base::FilePath CrashReportDatabaseWin::AttachmentsPath(const UUID& uuid) { + return base_dir_.Append(kAttachmentsDirectory).Append(uuid.ToString16()); +} + // static std::unique_ptr CrashReportDatabase::Initialize( const base::FilePath& path) { diff --git a/handler/win/crash_report_exception_handler.cc b/handler/win/crash_report_exception_handler.cc index d845c446ec..e735cdc99e 100644 --- a/handler/win/crash_report_exception_handler.cc +++ b/handler/win/crash_report_exception_handler.cc @@ -35,10 +35,12 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources) : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), + process_attachments_(process_attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() { @@ -114,6 +116,24 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException( return termination_code; } + if (process_attachments_) { + // Note that attachments are read at this point each time rather than once + // so that if the contents of the file has changed it will be re-read for + // each upload (e.g. in the case of a log file). + for (const auto& it : *process_attachments_) { + FileWriter* writer = new_report->AddAttachment(it.first); + if (writer) { + std::string contents; + if (!LoggingReadEntireFile(it.second, &contents)) { + // Not being able to read the file isn't considered fatal, and + // should not prevent the report from being processed. + continue; + } + writer->Write(contents.data(), contents.size()); + } + } + } + UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); diff --git a/handler/win/crash_report_exception_handler.h b/handler/win/crash_report_exception_handler.h index c2781de388..2439813b38 100644 --- a/handler/win/crash_report_exception_handler.h +++ b/handler/win/crash_report_exception_handler.h @@ -20,6 +20,7 @@ #include #include +#include "base/files/file_path.h" #include "base/macros.h" #include "handler/user_stream_data_source.h" #include "util/win/exception_handler_server.h" @@ -49,6 +50,10 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { //! To interoperate with Breakpad servers, the recommended practice is to //! specify values for the `"prod"` and `"ver"` keys as process //! annotations. + //! \param[in] process_attachments A map of file name keys to file paths to be + //! included in the report. Each time a report is written, the file paths + //! will be read in their entirety and included in the report using the + //! file name key as the name in the http upload. //! \param[in] user_stream_data_sources Data sources to be used to extend //! crash reports. For each crash report that is written, the data sources //! are called in turn. These data sources may contribute additional @@ -57,6 +62,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, + const std::map* process_attachments, const UserStreamDataSources* user_stream_data_sources); ~CrashReportExceptionHandler(); @@ -75,6 +81,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map* process_annotations_; // weak + const std::map* process_attachments_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); From 0630cedeb22459d8823d6f583b7672bb80753eb7 Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Tue, 27 Nov 2018 04:34:32 +0200 Subject: [PATCH 005/478] update CrashReportDatabaseTest --- client/crash_report_database_test.cc | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index 2dbb4fc12c..aed16ebdc9 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -20,7 +20,6 @@ #include "test/errors.h" #include "test/file.h" #include "test/filesystem.h" -#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "util/file/file_io.h" #include "util/file/filesystem.h" @@ -671,10 +670,6 @@ TEST_F(CrashReportDatabaseTest, RequestUpload) { } TEST_F(CrashReportDatabaseTest, Attachments) { -#if defined(OS_MACOSX) || defined(OS_WIN) - // Attachments aren't supported on Mac and Windows yet. - DISABLED_TEST(); -#else std::unique_ptr new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), CrashReportDatabase::kNoError); @@ -713,16 +708,9 @@ TEST_F(CrashReportDatabaseTest, Attachments) { char result_buffer[sizeof(test_data)]; result_attachments["some_file"]->Read(result_buffer, sizeof(result_buffer)); EXPECT_EQ(memcmp(test_data, result_buffer, sizeof(test_data)), 0); -#endif } TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { -#if defined(OS_MACOSX) || defined(OS_WIN) - // Attachments aren't supported on Mac and Windows yet. - DISABLED_TEST(); -#else - // TODO: This is using paths that are specific to the generic implementation - // and will need to be generalized for Mac and Windows. std::unique_ptr new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), CrashReportDatabase::kNoError); @@ -744,16 +732,25 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { ASSERT_TRUE(LoggingRemoveFile(report.file_path)); +// Additional check for Generic database +#if !defined(OS_MACOSX) && !defined(OS_WIN) ASSERT_TRUE(LoggingRemoveFile(base::FilePath( report.file_path.RemoveFinalExtension().value() + ".meta"))); +#endif ASSERT_EQ(db()->LookUpCrashReport(uuid, &report), CrashReportDatabase::kReportNotFound); +#ifdef OS_WIN + auto uuid_str = uuid.ToString16(); +#else + auto uuid_str = uuid.ToString(); +#endif + base::FilePath report_attachments_dir( - path().Append("attachments").Append(uuid.ToString())); - base::FilePath file_path1(report_attachments_dir.Append("file1")); - base::FilePath file_path2(report_attachments_dir.Append("file2")); + path().Append(FILE_PATH_LITERAL("attachments")).Append(uuid_str)); + base::FilePath file_path1(report_attachments_dir.Append(FILE_PATH_LITERAL("file1"))); + base::FilePath file_path2(report_attachments_dir.Append(FILE_PATH_LITERAL("file2"))); EXPECT_TRUE(FileExists(file_path1)); EXPECT_TRUE(FileExists(file_path1)); @@ -762,7 +759,6 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { EXPECT_FALSE(FileExists(file_path1)); EXPECT_FALSE(FileExists(file_path2)); EXPECT_FALSE(FileExists(report_attachments_dir)); -#endif } // This test uses knowledge of the database format to break it, so it only From 1fc0ce3a5970944481fe80f7a05b0983ef1b4499 Mon Sep 17 00:00:00 2001 From: Anton Ovchinnikov Date: Mon, 4 Mar 2019 19:54:37 +0100 Subject: [PATCH 006/478] feat: Add StartHandlerWithAttachments with examples --- Makefile | 4 ++ README.md | 4 ++ client/crash_report_database_win.cc | 6 +-- client/crashpad_client.h | 6 +-- client/crashpad_client_mac.cc | 26 +++++++++ client/crashpad_client_win.cc | 27 ++++++++++ example.cpp | 81 +++++++++++++++++++++++++++++ handler/handler_main.cc | 18 +++---- 8 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 example.cpp diff --git a/Makefile b/Makefile index b741664b24..80a41c2b2c 100644 --- a/Makefile +++ b/Makefile @@ -23,3 +23,7 @@ example: -framework Foundation -framework Security -framework CoreText \ -framework CoreGraphics -framework IOKit -lbsm .PHONY: example + +gen-sentry-patch: + git format-patch --stdout master...HEAD > getsentry.patch +.PHONY: get-sentry-patch diff --git a/README.md b/README.md index 0798f000bb..1da5384fd5 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,7 @@ https://chromium.googlesource.com/crashpad/crashpad. File attachments support for MacOS and Windows. Based on changes made in https://github.com/Youw/crashpad/, distributed with Apache 2.0 License. + +Generating patch: + + git format-patch --stdout master...HEAD > getsentry.patch diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index af2c0a8240..a78b7cee03 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -675,13 +675,13 @@ void CrashReportDatabase::UploadReport::InitializeAttachments() { while ((dir_result = reader.NextFile(&filename)) == DirectoryReader::Result::kSuccess) { const base::FilePath filepath(attachments_dir.Append(filename)); - std::unique_ptr reader(std::make_unique()); - if (!reader->Open(filepath)) { + std::unique_ptr fileReader(std::make_unique()); + if (!fileReader->Open(filepath)) { LOG(ERROR) << "attachment " << base::UTF16ToUTF8(filepath.value()) << " couldn't be opened, skipping"; continue; } - attachment_readers_.emplace_back(std::move(reader)); + attachment_readers_.emplace_back(std::move(fileReader)); attachment_map_[base::UTF16ToUTF8(filename.value())] = attachment_readers_.back().get(); } diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 3275d58dc2..7d91b59577 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -112,18 +112,18 @@ class CrashpadClient { bool restartable, bool asynchronous_start); -#if defined(OS_MACOSX) +#if defined(OS_WIN) || defined(OS_MACOSX) bool StartHandlerWithAttachments( const base::FilePath& handler, const base::FilePath& database, const base::FilePath& metrics_dir, const std::string& url, const std::map& annotations, - const std::map& fileAttachments, + const std::map& fileAttachments, const std::vector& arguments, bool restartable, bool asynchronous_start); -#endif +#endif // OS_WIN || OS_MACOSX #if defined(OS_ANDROID) || DOXYGEN //! \brief Installs a signal handler to execute `/system/bin/app_process` and diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 22bd538c96..164cbe3008 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -465,6 +465,32 @@ bool CrashpadClient::StartHandler( return true; } +bool CrashpadClient::StartHandlerWithAttachments( + const base::FilePath& handler, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map& annotations, + const std::map& fileAttachments, + const std::vector& arguments, + bool restartable, + bool asynchronous_start) { + std::vector updated_arguments = arguments; + for (const auto& kv: fileAttachments) { + std::string attachmentArg = "--attachment=" + kv.first + "=" + kv.second.value(); + updated_arguments.push_back(attachmentArg); + } + + return StartHandler(handler, + database, + metrics_dir, + url, + annotations, + updated_arguments, + restartable, + asynchronous_start); +} + bool CrashpadClient::SetHandlerMachService(const std::string& service_name) { base::mac::ScopedMachSendRight exception_port(BootstrapLookUp(service_name)); if (!exception_port.is_valid()) { diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 143dc4f1bb..106954db59 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -651,6 +651,33 @@ bool CrashpadClient::StartHandler( } } +bool CrashpadClient::StartHandlerWithAttachments( + const base::FilePath& handler, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map& annotations, + const std::map& fileAttachments, + const std::vector& arguments, + bool restartable, + bool asynchronous_start) { + std::vector updated_arguments = arguments; + for (const auto& kv : fileAttachments) { + std::string attachmentArg = + "--attachment=" + kv.first + "=" + base::UTF16ToUTF8(kv.second.value()); + updated_arguments.push_back(attachmentArg); + } + + return StartHandler(handler, + database, + metrics_dir, + url, + annotations, + updated_arguments, + restartable, + asynchronous_start); +} + bool CrashpadClient::SetHandlerIPCPipe(const std::wstring& ipc_pipe) { DCHECK(ipc_pipe_.empty()); DCHECK(!ipc_pipe.empty()); diff --git a/example.cpp b/example.cpp new file mode 100644 index 0000000000..474ae999bb --- /dev/null +++ b/example.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "client/crash_report_database.h" +#include "client/crashpad_client.h" +#include "client/crashpad_info.h" +#include "client/settings.h" + +using namespace crashpad; + +int init_crashpad() { + // Cache directory that will store crashpad information and minidumps + base::FilePath database("crashpad.db"); + // Path to the out-of-process handler executable + base::FilePath handler("./out/Default/crashpad_handler"); + // URL used to submit minidumps to + std::string url( + "http://localhost:8000/api/5/minidump/" + "?sentry_key=36811373240a4fc6b25f3040693462d5"); + // Optional annotations passed via --annotations to the handler + std::map annotations; + // Optional arguments to pass to the handler + std::vector arguments; + + arguments.push_back("--no-rate-limit"); + + std::map attachments; + attachments["attch_log_bla.txt"] = base::FilePath("/tmp/log.txt"); + + CrashpadClient client; + bool success = client.StartHandlerWithAttachments(handler, + database, + database, + url, + annotations, + attachments, + arguments, + /* restartable */ true, + /* asynchronous_start */ false); + + if (success) { + printf("Started client handler.\n"); + } else { + printf("Failed to start client handler.\n"); + } + + if (!success) { + return 1; + } + + std::unique_ptr db = + CrashReportDatabase::Initialize(database); + + if (db != nullptr && db->GetSettings() != nullptr) { + db->GetSettings()->SetUploadsEnabled(true); + } + + // Ensure that the simple annotations dictionary is set in the client. + CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo(); + + return 0; +} + +void crash(uint sleep_sec) { + std::cerr << "Prepare to crash, sleeping for " << sleep_sec << " second(s)\n"; + std::this_thread::sleep_for(std::chrono::seconds(sleep_sec)); + memset((char*)0x0, 1, 100); +} + +int main(int args, char* argv[]) { + init_crashpad(); + + const uint sleep_sec = args > 1 ? std::stoi(argv[1]) : 1; + crash(sleep_sec); +} diff --git a/handler/handler_main.cc b/handler/handler_main.cc index b223c9095e..dd8fc9dad6 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -149,9 +149,9 @@ void Usage(const base::FilePath& me) { #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" -#if defined(OS_WIN) || defined(OS_MACOSX) +#if !defined(OS_FUCHSIA) " --attachment=NAME=PATH attach a copy of a file, along with a crash dump\n" -#endif // OS_WIN || OS_MACOSX +#endif " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); @@ -581,9 +581,9 @@ int HandlerMain(int argc, kOptionSanitizationInformation, #endif kOptionURL, -#if defined(OS_WIN) || defined(OS_MACOSX) +#if !defined(OS_FUCHSIA) kOptionAttachment, -#endif // OS_WIN || OS_MACOSX +#endif // Standard options. kOptionHelp = -2, @@ -643,9 +643,9 @@ int HandlerMain(int argc, kOptionSanitizationInformation}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, -#if defined(OS_WIN) || defined(OS_MACOSX) +#if !defined(OS_FUCHSIA) {"attachment", required_argument, nullptr, kOptionAttachment}, -#endif // OS_WIN || O_MACOSX +#endif {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, {nullptr, 0, nullptr, 0}, @@ -783,14 +783,14 @@ int HandlerMain(int argc, options.url = optarg; break; } -#if defined(OS_WIN) || defined(OS_MACOSX) +#if !defined(OS_FUCHSIA) case kOptionAttachment: { if (!AddKeyValueToMap(&options.attachments, optarg, "--attachment")) { return ExitFailure(); } break; } -#endif // OS_WIN || OS_MACOSX +#endif case kOptionHelp: { Usage(me); MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); @@ -917,7 +917,7 @@ int HandlerMain(int argc, #if defined(OS_FUCHSIA) // TODO(scottmg): Process level file attachments, and for all platforms. nullptr, -#elif defined(OS_WIN) || defined(OS_MACOSX) +#else &options.attachments, #endif user_stream_sources); From 6e7e91d167967f819a20e02bd8b98ecba4bb1a63 Mon Sep 17 00:00:00 2001 From: Anton Ovchinnikov Date: Fri, 22 Mar 2019 17:52:37 +0100 Subject: [PATCH 007/478] feat: Implement basic StartHandlerWithAttachments for Linux --- client/crashpad_client.h | 4 ++-- client/crashpad_client_linux.cc | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 7d91b59577..f60be213d4 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -112,7 +112,7 @@ class CrashpadClient { bool restartable, bool asynchronous_start); -#if defined(OS_WIN) || defined(OS_MACOSX) +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) bool StartHandlerWithAttachments( const base::FilePath& handler, const base::FilePath& database, @@ -123,7 +123,7 @@ class CrashpadClient { const std::vector& arguments, bool restartable, bool asynchronous_start); -#endif // OS_WIN || OS_MACOSX +#endif // OS_WIN || OS_MACOSX || OS_LINUX #if defined(OS_ANDROID) || DOXYGEN //! \brief Installs a signal handler to execute `/system/bin/app_process` and diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index fe5798a534..37ea10eed6 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -238,6 +238,31 @@ bool CrashpadClient::StartHandler( return false; } +bool CrashpadClient::StartHandlerWithAttachments( + const base::FilePath& handler, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map& annotations, + const std::map& fileAttachments, + const std::vector& arguments, + bool restartable, + bool asynchronous_start) { + std::vector updated_arguments = arguments; + for (const auto& kv: fileAttachments) { + std::string attachmentArg = "--attachment=" + kv.first + "=" + kv.second.value(); + updated_arguments.push_back(attachmentArg); + } + + // FIXME this is not the same as calling StartHandler on e.g. Mac + return CrashpadClient::StartHandlerAtCrash(handler, + database, + metrics_dir, + url, + annotations, + updated_arguments); +} + #if defined(OS_ANDROID) // static From 421c78e2663ae8e5501319a9975c281ea0cb5b1a Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Mon, 9 Dec 2019 13:59:46 +0100 Subject: [PATCH 008/478] Add throws declaration to memfd_create --- compat/linux/sys/mman.cc | 2 +- compat/linux/sys/mman.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/linux/sys/mman.cc b/compat/linux/sys/mman.cc index 12aaa2c7df..044dbcaee7 100644 --- a/compat/linux/sys/mman.cc +++ b/compat/linux/sys/mman.cc @@ -22,7 +22,7 @@ extern "C" { -int memfd_create(const char* name, unsigned int flags) { +int memfd_create(const char* name, unsigned int flags) __THROW { using MemfdCreateType = int (*)(const char*, int); static const MemfdCreateType next_memfd_create = reinterpret_cast(dlsym(RTLD_NEXT, "memfd_create")); diff --git a/compat/linux/sys/mman.h b/compat/linux/sys/mman.h index 61c55d7b95..43155da541 100644 --- a/compat/linux/sys/mman.h +++ b/compat/linux/sys/mman.h @@ -29,7 +29,7 @@ extern "C" { #endif -int memfd_create(const char* name, unsigned int flags); +int memfd_create(const char* name, unsigned int flags) __THROW; #ifdef __cplusplus } // extern "C" From 49414c4f67ba45f75071465d2228b802e6507735 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Mon, 9 Dec 2019 14:28:47 +0100 Subject: [PATCH 009/478] Define __THROW in case it is undefined --- compat/linux/sys/mman.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/linux/sys/mman.h b/compat/linux/sys/mman.h index 43155da541..cc5e745e66 100644 --- a/compat/linux/sys/mman.h +++ b/compat/linux/sys/mman.h @@ -25,6 +25,10 @@ // which doesn't. #if defined(__GLIBC__) +#ifndef __THROW +#define __THROW +#endif + #ifdef __cplusplus extern "C" { #endif From 8a2ddfc0a475bff9e25bfc7af693bac373adebe3 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 21 Feb 2020 14:03:37 +0100 Subject: [PATCH 010/478] build: Add CMake files for crashpad (#2) * build: add CMake files for crashpad * add explicit submodule for mini_chromium * make cmake builds work on windows * review feedback, add separate getsentry README * better document changes, add update instructions --- .gitignore | 2 - .gitmodules | 6 + CMakeLists.txt | 78 +++++ Makefile | 15 +- README.getsentry.md | 54 ++++ README.md | 5 +- client/CMakeLists.txt | 58 ++++ compat/CMakeLists.txt | 89 ++++++ handler/CMakeLists.txt | 63 ++++ minidump/CMakeLists.txt | 65 ++++ snapshot/CMakeLists.txt | 181 ++++++++++++ third_party/getopt/CMakeLists.txt | 6 + third_party/mini_chromium/CMakeLists.txt | 136 +++++++++ third_party/mini_chromium/mini_chromium | 1 + third_party/zlib/CMakeLists.txt | 54 ++++ third_party/zlib/zlib | 1 + tools/CMakeLists.txt | 11 + util/CMakeLists.txt | 361 +++++++++++++++++++++++ 18 files changed, 1177 insertions(+), 9 deletions(-) create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 README.getsentry.md create mode 100644 client/CMakeLists.txt create mode 100644 compat/CMakeLists.txt create mode 100644 handler/CMakeLists.txt create mode 100644 minidump/CMakeLists.txt create mode 100644 snapshot/CMakeLists.txt create mode 100644 third_party/getopt/CMakeLists.txt create mode 100644 third_party/mini_chromium/CMakeLists.txt create mode 160000 third_party/mini_chromium/mini_chromium create mode 100644 third_party/zlib/CMakeLists.txt create mode 160000 third_party/zlib/zlib create mode 100644 tools/CMakeLists.txt create mode 100644 util/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 90038f1d21..6cfc15a8d1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,5 @@ /third_party/linux/sysroot /third_party/lss/lss /third_party/gyp/gyp -/third_party/mini_chromium/mini_chromium -/third_party/zlib/zlib /xcodebuild tags diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..6b27a29859 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "third_party/mini_chromium/mini_chromium"] + path = third_party/mini_chromium/mini_chromium + url = https://chromium.googlesource.com/chromium/mini_chromium +[submodule "third_party/zlib/zlib"] + path = third_party/zlib/zlib + url = https://chromium.googlesource.com/chromium/src/third_party/zlib diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..5b2d6c1dc3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.0) +project(crashpad LANGUAGES C CXX) + +if(WIN32) + enable_language(ASM_MASM) +else() + enable_language(ASM) +endif() + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(LINUX TRUE) +endif() + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third_party/mini_chromium/mini_chromium") + +# These should really be in `compat`, but we want them for the whole project +if(APPLE) + include_directories(SYSTEM "compat/mac") +else() + include_directories(PUBLIC "compat/non_mac") +endif() + +if(LINUX OR ANDROID) + include_directories(SYSTEM "compat/linux") +endif() +if(ANDROID) + include_directories(SYSTEM "compat/android") +endif() + +if(WIN32) + include_directories(SYSTEM "compat/win") +else() + include_directories(PUBLIC "compat/non_win") +endif() + +if(NOT LINUX AND NOT ANDROID) + include_directories(SYSTEM "compat/non_elf") +endif() + +if(WIN32) + add_definitions( + /DNOMINMAX + /DUNICODE + /DWIN32_LEAN_AND_MEAN + /D_CRT_SECURE_NO_WARNINGS + /D_HAS_EXCEPTIONS=0 + /D_UNICODE + /FS + /W4 + /WX + /Zi + /bigobj # Support larger number of sections in obj file. + /wd4100 # Unreferenced formal parameter. + /wd4127 # Conditional expression is constant. + /wd4324 # Structure was padded due to alignment specifier. + /wd4351 # New behavior: elements of array will be default initialized. + /wd4577 # 'noexcept' used with no exception handling mode specified. + /wd4996 # 'X' was declared deprecated. + ) +endif() + +add_subdirectory(client) +add_subdirectory(compat) +add_subdirectory(handler) +add_subdirectory(minidump) +add_subdirectory(snapshot) +add_subdirectory(tools) +add_subdirectory(util) +add_subdirectory(third_party/mini_chromium) + +if(WIN32) + add_subdirectory(third_party/getopt) + add_subdirectory(third_party/zlib) +endif() diff --git a/Makefile b/Makefile index 80a41c2b2c..6d88f6fc44 100644 --- a/Makefile +++ b/Makefile @@ -4,15 +4,22 @@ PATH := $(PWD)/../depot_tools:$(PATH) all: echo 'Nothing to do' && exit 1 -build: +build-with-gn: gn gen out/Default ninja -C out/Default -.PHONY: build +.PHONY: build-with-gn -update: +build-with-cmake: + mkdir -p cmakebuild + cd cmakebuild; cmake .. + cmake --build cmakebuild --parallel +.PHONY: build-with-cmake + +update-with-gclient: gclient sync +.PHONY: update-with-gclient -example: +example: build-with-gn g++ -g \ -o example example.cpp \ -I. -I./third_party/mini_chromium/mini_chromium \ diff --git a/README.getsentry.md b/README.getsentry.md new file mode 100644 index 0000000000..a0af84edb4 --- /dev/null +++ b/README.getsentry.md @@ -0,0 +1,54 @@ +# Sentry Modifications + +- File attachments support for MacOS and Windows. Based on changes made in + https://github.com/Youw/crashpad/, distributed with Apache 2.0 License. +- Add `throws` declaration to `memfd_create` for compatibility with different + libc versions. +- Build System Changes Listed Below + +# Build System Changes + +In order to minimize external dependencies, and to better integrate with +`sentry-native`, this fork replaced usage of `depo_tools` with explicit +submodules, and added CMake files for building. + +Both submodules and CMake files currently only support building on macOS and +Windows, and do only export the necessary libraries and executables to +integrate the crashpad client. + +When updating this fork, make sure to keep the files in sync, as explained +below. + +## Submodules + +For macOS and Windows support, only `third_party/mini_chromium` and +`third_party/zlib` are needed. + +The specific submodule commit hashes can be found in the `./DEPS` file. + +## CMake Integration + +To allow building crashpad with CMake, the following CMake files were created +by manually translating the `BUILD.gn` files in the same folders (and following +included files): + +- `./CMakeLists.txt` +- `./client/CMakeLists.txt` +- `./compat/CMakeLists.txt` +- `./handler/CMakeLists.txt` +- `./minidump/CMakeLists.txt` +- `./snapshot/CMakeLists.txt` +- `./third_party/getopt/CMakeLists.txt` +- `./third_party/mini_chromium/CMakeLists.txt` +- `./third_party/lib/CMakeLists.txt` +- `./tools/CMakeLists.txt` +- `./util/CMakeLists.txt` + +The important thing here is to keep the list of source files in sync when +updating. + +# How To Update + +- Bump the submodules to the commit hashes specified in `./DEPS` +- Go through the changes in `BUILD.gn` files, and apply them to the + corresponding `CMakeLists.txt`. See the list above. diff --git a/README.md b/README.md index 1da5384fd5..06a5d046ec 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,8 @@ https://chromium.googlesource.com/crashpad/crashpad. ## Sentry modifications -File attachments support for MacOS and Windows. - -Based on changes made in https://github.com/Youw/crashpad/, distributed with Apache 2.0 License. +See [README.getsentry.md](README.getsentry.md) for more information on the +changes, and on maintaining the fork. Generating patch: diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000000..940e268823 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,58 @@ +list(APPEND CLIENT_SOURCES + annotation.cc + annotation.h + annotation_list.cc + annotation_list.h + crash_report_database.cc + crash_report_database.h + crashpad_client.h + crashpad_info.cc + crashpad_info.h + prune_crash_reports.cc + prune_crash_reports.h + settings.cc + settings.h + simple_address_range_bag.h + simple_string_dictionary.h + simulate_crash.h +) + +if(APPLE) + list(APPEND CLIENT_SOURCES + crash_report_database_mac.mm + crashpad_client_mac.cc + simulate_crash_mac.cc + simulate_crash_mac.h + ) +endif() + +if(LINUX OR ANDROID) + list(APPEND CLIENT_SOURCES + crashpad_client_linux.cc + simulate_crash_linux.h + client_argv_handling.cc + client_argv_handling.h + crashpad_info_note.S + crash_report_database_generic.cc + ) +endif() + +if(WIN32) + list(APPEND CLIENT_SOURCES + crash_report_database_win.cc + crashpad_client_win.cc + simulate_crash_win.h + ) +endif() + +add_library(crashpad_client STATIC ${CLIENT_SOURCES}) +target_link_libraries(crashpad_client + crashpad_compat + crashpad_util + mini_chromium +) + +if(WIN32) + target_link_libraries(crashpad_client "rpcrt4") + target_compile_options(crashpad_client PUBLIC "/wd4201") +endif() diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt new file mode 100644 index 0000000000..576bde10f3 --- /dev/null +++ b/compat/CMakeLists.txt @@ -0,0 +1,89 @@ +list(APPEND COMPAT_SOURCES "") + +if(APPLE) + list(APPEND COMPAT_SOURCES + mac/AvailabilityMacros.h + mac/kern/exc_resource.h + mac/mach-o/loader.h + mac/mach/mach.h + mac/sys/resource.h + ) +else() + list(APPEND COMPAT_SOURCES + non_mac/mach-o/loader.h + non_mac/mach/mach.h + non_mac/mach/machine.h + non_mac/mach/vm_prot.h + ) +endif() + +if(LINUX OR ANDROID) + list(APPEND COMPAT_SOURCES + linux/signal.h + linux/sys/mman.cc + linux/sys/mman.h + linux/sys/ptrace.h + linux/sys/user.h + ) +endif() + +if(ANDROID) + list(APPEND COMPAT_SOURCES + android/android/api-level.cc + android/android/api-level.h + android/dlfcn_internal.cc + android/dlfcn_internal.h + android/elf.h + android/linux/elf.h + android/linux/prctl.h + android/linux/ptrace.h + android/sched.h + android/sys/epoll.cc + android/sys/epoll.h + android/sys/mman.cc + android/sys/mman.h + android/sys/syscall.h + android/sys/user.h + ) +endif() + +if(WIN32) + list(APPEND COMPAT_SOURCES + win/getopt.h + win/strings.cc + win/strings.h + win/sys/types.h + win/time.cc + win/time.h + win/winbase.h + win/winnt.h + win/winternl.h + ) +else() + list(APPEND COMPAT_SOURCES + non_win/dbghelp.h + non_win/minwinbase.h + non_win/timezoneapi.h + non_win/verrsrc.h + non_win/windows.h + non_win/winnt.h + ) +endif() + +if(NOT LINUX AND NOT ANDROID) + list(APPEND COMPAT_SOURCES + non_elf/elf.h + ) +endif() + +if(APPLE) + add_library(crashpad_compat INTERFACE) + list(TRANSFORM COMPAT_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") + target_sources(crashpad_compat INTERFACE ${COMPAT_SOURCES}) +else() + add_library(crashpad_compat STATIC ${COMPAT_SOURCES}) +endif() + +if(WIN32) + target_link_libraries(crashpad_compat getopt) +endif() diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt new file mode 100644 index 0000000000..b751a2ee09 --- /dev/null +++ b/handler/CMakeLists.txt @@ -0,0 +1,63 @@ +list(APPEND HANDLER_SOURCES + main.cc + crash_report_upload_thread.cc + crash_report_upload_thread.h + handler_main.cc + handler_main.h + minidump_to_upload_parameters.cc + minidump_to_upload_parameters.h + prune_crash_reports_thread.cc + prune_crash_reports_thread.h + user_stream_data_source.cc + user_stream_data_source.h +) + +if(APPLE) + list(APPEND HANDLER_SOURCES + mac/crash_report_exception_handler.cc + mac/crash_report_exception_handler.h + mac/exception_handler_server.cc + mac/exception_handler_server.h + mac/file_limit_annotation.cc + mac/file_limit_annotation.h + ) +endif() + +if(LINUX OR ANDROID) + list(APPEND HANDLER_SOURCES + linux/capture_snapshot.cc + linux/capture_snapshot.h + linux/crash_report_exception_handler.cc + linux/crash_report_exception_handler.h + linux/exception_handler_server.cc + linux/exception_handler_server.h + ) +endif() + +if(LINUX) + list(APPEND HANDLER_SOURCES + linux/cros_crash_report_exception_handler.cc + linux/cros_crash_report_exception_handler.h + ) +endif() + +if(WIN32) + list(APPEND HANDLER_SOURCES + win/crash_report_exception_handler.cc + win/crash_report_exception_handler.h + ) +endif() + +add_executable(crashpad_handler ${HANDLER_SOURCES}) +target_link_libraries(crashpad_handler + crashpad_client + crashpad_minidump + crashpad_snapshot + crashpad_tools + crashpad_util + mini_chromium +) + +if(WIN32) + target_compile_options(crashpad_handler PUBLIC "/wd4201") +endif() diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt new file mode 100644 index 0000000000..75ab21d57c --- /dev/null +++ b/minidump/CMakeLists.txt @@ -0,0 +1,65 @@ +list(APPEND MINIDUMP_SOURCES + minidump_annotation_writer.cc + minidump_annotation_writer.h + minidump_byte_array_writer.cc + minidump_byte_array_writer.h + minidump_context.h + minidump_context_writer.cc + minidump_context_writer.h + minidump_crashpad_info_writer.cc + minidump_crashpad_info_writer.h + minidump_exception_writer.cc + minidump_exception_writer.h + minidump_extensions.cc + minidump_extensions.h + minidump_file_writer.cc + minidump_file_writer.h + minidump_handle_writer.cc + minidump_handle_writer.h + minidump_memory_info_writer.cc + minidump_memory_info_writer.h + minidump_memory_writer.cc + minidump_memory_writer.h + minidump_misc_info_writer.cc + minidump_misc_info_writer.h + minidump_module_crashpad_info_writer.cc + minidump_module_crashpad_info_writer.h + minidump_module_writer.cc + minidump_module_writer.h + minidump_rva_list_writer.cc + minidump_rva_list_writer.h + minidump_simple_string_dictionary_writer.cc + minidump_simple_string_dictionary_writer.h + minidump_stream_writer.cc + minidump_stream_writer.h + minidump_string_writer.cc + minidump_string_writer.h + minidump_system_info_writer.cc + minidump_system_info_writer.h + minidump_thread_id_map.cc + minidump_thread_id_map.h + minidump_thread_writer.cc + minidump_thread_writer.h + minidump_unloaded_module_writer.cc + minidump_unloaded_module_writer.h + minidump_user_extension_stream_data_source.cc + minidump_user_extension_stream_data_source.h + minidump_user_stream_writer.cc + minidump_user_stream_writer.h + minidump_writable.cc + minidump_writable.h + minidump_writer_util.cc + minidump_writer_util.h +) + +add_library(crashpad_minidump STATIC ${MINIDUMP_SOURCES}) +target_link_libraries(crashpad_minidump + crashpad_compat + crashpad_snapshot + crashpad_util + mini_chromium +) + +if(WIN32) + target_compile_options(crashpad_minidump PUBLIC "/wd4201" "/wd4324") +endif() diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt new file mode 100644 index 0000000000..f349514b86 --- /dev/null +++ b/snapshot/CMakeLists.txt @@ -0,0 +1,181 @@ +list(APPEND SNAPSHOT_SOURCES + annotation_snapshot.cc + annotation_snapshot.h + capture_memory.cc + capture_memory.h + cpu_architecture.h + cpu_context.cc + cpu_context.h + crashpad_info_client_options.cc + crashpad_info_client_options.h + exception_snapshot.h + handle_snapshot.cc + handle_snapshot.h + memory_snapshot.cc + memory_snapshot.h + memory_snapshot_generic.h + minidump/exception_snapshot_minidump.cc + minidump/exception_snapshot_minidump.h + minidump/memory_snapshot_minidump.cc + minidump/memory_snapshot_minidump.h + minidump/minidump_annotation_reader.cc + minidump/minidump_annotation_reader.h + minidump/minidump_context_converter.cc + minidump/minidump_context_converter.h + minidump/minidump_simple_string_dictionary_reader.cc + minidump/minidump_simple_string_dictionary_reader.h + minidump/minidump_stream.h + minidump/minidump_string_list_reader.cc + minidump/minidump_string_list_reader.h + minidump/minidump_string_reader.cc + minidump/minidump_string_reader.h + minidump/module_snapshot_minidump.cc + minidump/module_snapshot_minidump.h + minidump/process_snapshot_minidump.cc + minidump/process_snapshot_minidump.h + minidump/system_snapshot_minidump.cc + minidump/system_snapshot_minidump.h + minidump/thread_snapshot_minidump.cc + minidump/thread_snapshot_minidump.h + module_snapshot.h + process_snapshot.h + snapshot_constants.h + system_snapshot.h + thread_snapshot.h + unloaded_module_snapshot.cc + unloaded_module_snapshot.h +) + + +if(APPLE) + list(APPEND SNAPSHOT_SOURCES + posix/timezone.cc + posix/timezone.h + mac/cpu_context_mac.cc + mac/cpu_context_mac.h + mac/exception_snapshot_mac.cc + mac/exception_snapshot_mac.h + mac/mach_o_image_annotations_reader.cc + mac/mach_o_image_annotations_reader.h + mac/mach_o_image_reader.cc + mac/mach_o_image_reader.h + mac/mach_o_image_segment_reader.cc + mac/mach_o_image_segment_reader.h + mac/mach_o_image_symbol_table_reader.cc + mac/mach_o_image_symbol_table_reader.h + mac/module_snapshot_mac.cc + mac/module_snapshot_mac.h + mac/process_reader_mac.cc + mac/process_reader_mac.h + mac/process_snapshot_mac.cc + mac/process_snapshot_mac.h + mac/process_types.cc + mac/process_types.h + mac/process_types/custom.cc + mac/process_types/flavors.h + mac/process_types/internal.h + mac/process_types/traits.h + mac/system_snapshot_mac.cc + mac/system_snapshot_mac.h + mac/thread_snapshot_mac.cc + mac/thread_snapshot_mac.h + ) +else() + list(APPEND SNAPSHOT_SOURCES + crashpad_types/crashpad_info_reader.cc + crashpad_types/crashpad_info_reader.h + ) +endif() + +if(LINUX OR ANDROID) + list(APPEND SNAPSHOT_SOURCES + posix/timezone.cc + posix/timezone.h + linux/cpu_context_linux.cc + linux/cpu_context_linux.h + linux/debug_rendezvous.cc + linux/debug_rendezvous.h + linux/exception_snapshot_linux.cc + linux/exception_snapshot_linux.h + linux/process_reader_linux.cc + linux/process_reader_linux.h + linux/process_snapshot_linux.cc + linux/process_snapshot_linux.h + linux/signal_context.h + linux/system_snapshot_linux.cc + linux/system_snapshot_linux.h + linux/thread_snapshot_linux.cc + linux/thread_snapshot_linux.h + sanitized/memory_snapshot_sanitized.cc + sanitized/memory_snapshot_sanitized.h + sanitized/module_snapshot_sanitized.cc + sanitized/module_snapshot_sanitized.h + sanitized/process_snapshot_sanitized.cc + sanitized/process_snapshot_sanitized.h + sanitized/sanitization_information.cc + sanitized/sanitization_information.h + sanitized/thread_snapshot_sanitized.cc + sanitized/thread_snapshot_sanitized.h + crashpad_types/image_annotation_reader.cc + crashpad_types/image_annotation_reader.h + elf/elf_dynamic_array_reader.cc + elf/elf_dynamic_array_reader.h + elf/elf_image_reader.cc + elf/elf_image_reader.h + elf/elf_symbol_table_reader.cc + elf/elf_symbol_table_reader.h + elf/module_snapshot_elf.cc + elf/module_snapshot_elf.h + ) +endif() + +if(WIN32) + list(APPEND SNAPSHOT_SOURCES + win/capture_memory_delegate_win.cc + win/capture_memory_delegate_win.h + win/cpu_context_win.cc + win/cpu_context_win.h + win/exception_snapshot_win.cc + win/exception_snapshot_win.h + win/memory_map_region_snapshot_win.cc + win/memory_map_region_snapshot_win.h + win/module_snapshot_win.cc + win/module_snapshot_win.h + win/pe_image_annotations_reader.cc + win/pe_image_annotations_reader.h + win/pe_image_reader.cc + win/pe_image_reader.h + win/pe_image_resource_reader.cc + win/pe_image_resource_reader.h + win/process_reader_win.cc + win/process_reader_win.h + win/process_snapshot_win.cc + win/process_snapshot_win.h + win/process_subrange_reader.cc + win/process_subrange_reader.h + win/system_snapshot_win.cc + win/system_snapshot_win.h + win/thread_snapshot_win.cc + win/thread_snapshot_win.h + ) +endif() + +# TODO: if(x86) + list(APPEND SNAPSHOT_SOURCES + x86/cpuid_reader.cc + x86/cpuid_reader.h + ) +#endif() + +add_library(crashpad_snapshot STATIC ${SNAPSHOT_SOURCES}) +target_link_libraries(crashpad_snapshot + crashpad_client + crashpad_compat + crashpad_util + mini_chromium +) + +if(WIN32) + target_link_libraries(crashpad_snapshot "powrprof") + target_compile_options(crashpad_snapshot PUBLIC "/wd4201") +endif() diff --git a/third_party/getopt/CMakeLists.txt b/third_party/getopt/CMakeLists.txt new file mode 100644 index 0000000000..7671ca0416 --- /dev/null +++ b/third_party/getopt/CMakeLists.txt @@ -0,0 +1,6 @@ +list(APPEND GETOPT_SOURCES + getopt.cc + getopt.h +) + +add_library(getopt STATIC ${GETOPT_SOURCES}) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt new file mode 100644 index 0000000000..a2fb8d5381 --- /dev/null +++ b/third_party/mini_chromium/CMakeLists.txt @@ -0,0 +1,136 @@ +list(APPEND MINI_CHROMIUM_SOURCES + ../build/build_config.h + atomicops.h + atomicops_internals_atomicword_compat.h + atomicops_internals_portable.h + auto_reset.h + bit_cast.h + compiler_specific.h + debug/alias.cc + debug/alias.h + files/file_path.cc + files/file_path.h + files/file_util.h + files/scoped_file.cc + files/scoped_file.h + format_macros.h + logging.cc + logging.h + macros.h + memory/free_deleter.h + memory/scoped_policy.h + metrics/histogram_functions.h + metrics/histogram_macros.h + metrics/persistent_histogram_allocator.h + numerics/checked_math.h + numerics/checked_math_impl.h + numerics/clamped_math.h + numerics/clamped_math_impl.h + numerics/safe_conversions.h + numerics/safe_conversions_arm_impl.h + numerics/safe_conversions_impl.h + numerics/safe_math.h + numerics/safe_math_arm_impl.h + numerics/safe_math_clang_gcc_impl.h + numerics/safe_math_shared_impl.h + process/memory.cc + process/memory.h + process/process_metrics.h + rand_util.cc + rand_util.h + scoped_clear_errno.h + scoped_generic.h + stl_util.h + strings/string16.cc + strings/string16.h + strings/string_number_conversions.cc + strings/string_number_conversions.h + strings/string_piece.h + strings/string_util.h + strings/stringprintf.cc + strings/stringprintf.h + strings/sys_string_conversions.h + strings/utf_string_conversion_utils.cc + strings/utf_string_conversion_utils.h + strings/utf_string_conversions.cc + strings/utf_string_conversions.h + synchronization/condition_variable.h + synchronization/lock.cc + synchronization/lock.h + synchronization/lock_impl.h + sys_byteorder.h + template_util.h + third_party/icu/icu_utf.cc + third_party/icu/icu_utf.h + threading/thread_local_storage.cc + threading/thread_local_storage.h +) + +if(APPLE) + list(APPEND MINI_CHROMIUM_SOURCES + mac/close_nocancel.cc + mac/foundation_util.h + mac/foundation_util.mm + mac/mach_logging.cc + mac/mach_logging.h + mac/scoped_cftyperef.h + mac/scoped_ioobject.h + mac/scoped_launch_data.h + mac/scoped_mach_port.cc + mac/scoped_mach_port.h + mac/scoped_mach_vm.cc + mac/scoped_mach_vm.h + mac/scoped_nsautorelease_pool.h + mac/scoped_nsautorelease_pool.mm + mac/scoped_nsobject.h + mac/scoped_typeref.h + strings/sys_string_conversions_mac.mm + ) +endif() + +if(WIN32) + list(APPEND MINI_CHROMIUM_SOURCES + process/process_metrics_win.cc + strings/string_util_win.cc + strings/string_util_win.h + synchronization/lock_impl_win.cc + threading/thread_local_storage_win.cc + ) +else() + list(APPEND MINI_CHROMIUM_SOURCES + files/file_util_posix.cc + posix/eintr_wrapper.h + posix/safe_strerror.cc + posix/safe_strerror.h + process/process_metrics_posix.cc + strings/string_util_posix.h + synchronization/condition_variable_posix.cc + synchronization/lock_impl_posix.cc + threading/thread_local_storage_posix.cc + ) +endif() + +list(TRANSFORM MINI_CHROMIUM_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/mini_chromium/base/") + +add_library(mini_chromium STATIC ${MINI_CHROMIUM_SOURCES}) + +if(APPLE) + target_link_libraries(mini_chromium PUBLIC "-framework ApplicationServices") + target_link_libraries(mini_chromium PUBLIC "-framework CoreFoundation") + target_link_libraries(mini_chromium PUBLIC "-framework Foundation") + target_link_libraries(mini_chromium PUBLIC "-framework IOKit") + target_link_libraries(mini_chromium PUBLIC "-framework Security") +endif() + +if(WIN32) + target_link_libraries(mini_chromium "advapi32" "kernel32") + target_compile_options(mini_chromium PUBLIC "/wd4201" "/wd4996") + target_compile_definitions(mini_chromium PUBLIC + NOMINMAX + UNICODE + WIN32_LEAN_AND_MEAN + _CRT_SECURE_NO_WARNINGS + _HAS_EXCEPTIONS=0 + _UNICODE + ) +endif() diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium new file mode 160000 index 0000000000..f8f1182adb --- /dev/null +++ b/third_party/mini_chromium/mini_chromium @@ -0,0 +1 @@ +Subproject commit f8f1182adb804675b2aa4fb3ce03f6f884fae474 diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt new file mode 100644 index 0000000000..d36dac5cf5 --- /dev/null +++ b/third_party/zlib/CMakeLists.txt @@ -0,0 +1,54 @@ +list(APPEND ZLIB_SOURCES + zlib/adler32.c + zlib/compress.c + zlib/crc32.c + zlib/crc32.h + zlib/deflate.c + zlib/deflate.h + zlib/gzclose.c + zlib/gzguts.h + zlib/gzlib.c + zlib/gzread.c + zlib/gzwrite.c + zlib/infback.c + zlib/inffast.c + zlib/inffast.h + zlib/inffixed.h + zlib/inflate.c + zlib/inflate.h + zlib/inftrees.c + zlib/inftrees.h + zlib/names.h + zlib/trees.c + zlib/trees.h + zlib/uncompr.c + zlib/zconf.h + zlib/zlib.h + zlib/zutil.c + zlib/zutil.h + zlib_crashpad.h +) + +# TODO: x86/x64 +list(APPEND ZLIB_SOURCES + zlib/crc_folding.c + zlib/fill_window_sse.c + zlib/x86.c + zlib/x86.h +) + +add_library(zlib STATIC ${ZLIB_SOURCES}) +target_compile_definitions(zlib PUBLIC HAVE_STDARG_H) + +include_directories(zlib) + +if(WIN32) + target_compile_options(zlib PUBLIC + "/wd4131" # uses old-style declarator + "/wd4244" # conversion from 't1' to 't2', possible loss of data + "/wd4245" # conversion from 't1' to 't2', signed/unsigned mismatch + "/wd4267" # conversion from 'size_t' to 't', possible loss of data + "/wd4324" # structure was padded due to alignment specifier + "/wd4702" # unreachable code + ) +endif() diff --git a/third_party/zlib/zlib b/third_party/zlib/zlib new file mode 160000 index 0000000000..13dc246a58 --- /dev/null +++ b/third_party/zlib/zlib @@ -0,0 +1 @@ +Subproject commit 13dc246a58e4b72104d35f9b1809af95221ebda7 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000000..f72f7e6e81 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,11 @@ +list(APPEND TOOLS_SOURCES + tool_support.cc + tool_support.h +) + +add_library(crashpad_tools STATIC ${TOOLS_SOURCES}) +target_link_libraries(crashpad_tools + mini_chromium +) + +# TODO: do we need any tool executables? diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt new file mode 100644 index 0000000000..95e70c227c --- /dev/null +++ b/util/CMakeLists.txt @@ -0,0 +1,361 @@ +list(APPEND UTIL_SOURCES + file/delimited_file_reader.cc + file/delimited_file_reader.h + file/directory_reader.h + file/file_io.cc + file/file_io.h + file/file_reader.cc + file/file_reader.h + file/file_seeker.cc + file/file_seeker.h + file/file_writer.cc + file/file_writer.h + file/filesystem.h + file/scoped_remove_file.cc + file/scoped_remove_file.h + file/string_file.cc + file/string_file.h + misc/address_sanitizer.h + misc/address_types.h + misc/arraysize.h + misc/as_underlying_type.h + misc/capture_context.h + misc/clock.h + misc/elf_note_types.h + misc/from_pointer_cast.h + misc/implicit_cast.h + misc/initialization_state.h + misc/initialization_state_dcheck.cc + misc/initialization_state_dcheck.h + misc/lexing.cc + misc/lexing.h + misc/memory_sanitizer.h + misc/metrics.cc + misc/metrics.h + misc/paths.h + misc/pdb_structures.cc + misc/pdb_structures.h + misc/random_string.cc + misc/random_string.h + misc/range_set.cc + misc/range_set.h + misc/reinterpret_bytes.cc + misc/reinterpret_bytes.h + misc/scoped_forbid_return.cc + misc/scoped_forbid_return.h + misc/symbolic_constants_common.h + misc/time.cc + misc/time.h + misc/tri_state.h + misc/uuid.cc + misc/uuid.h + misc/zlib.cc + misc/zlib.h + net/http_body.cc + net/http_body.h + net/http_body_gzip.cc + net/http_body_gzip.h + net/http_headers.h + net/http_multipart_builder.cc + net/http_multipart_builder.h + net/http_transport.cc + net/http_transport.h + net/url.cc + net/url.h + numeric/checked_address_range.cc + numeric/checked_address_range.h + numeric/checked_range.h + numeric/checked_vm_address_range.h + numeric/in_range_cast.h + numeric/int128.h + numeric/safe_assignment.h + process/process_id.h + process/process_memory.cc + process/process_memory.h + process/process_memory_native.h + process/process_memory_range.cc + process/process_memory_range.h + stdlib/aligned_allocator.cc + stdlib/aligned_allocator.h + stdlib/map_insert.h + stdlib/objc.h + stdlib/string_number_conversion.cc + stdlib/string_number_conversion.h + stdlib/strlcpy.cc + stdlib/strlcpy.h + stdlib/strnlen.cc + stdlib/strnlen.h + stdlib/thread_safe_vector.h + stream/output_stream_interface.h + stream/zlib_output_stream.cc + stream/zlib_output_stream.h + string/split_string.cc + string/split_string.h + synchronization/semaphore.h + thread/stoppable.h + thread/thread.cc + thread/thread.h + thread/thread_log_messages.cc + thread/thread_log_messages.h + thread/worker_thread.cc + thread/worker_thread.h +) + +if(NOT WIN32) + list(APPEND UTIL_SOURCES + file/directory_reader_posix.cc + file/file_io_posix.cc + file/filesystem_posix.cc + misc/clock_posix.cc + posix/close_stdio.cc + posix/close_stdio.h + posix/scoped_dir.cc + posix/scoped_dir.h + posix/scoped_mmap.cc + posix/scoped_mmap.h + posix/signals.cc + posix/signals.h + synchronization/semaphore_posix.cc + thread/thread_posix.cc + posix/close_multiple.cc + posix/close_multiple.h + posix/double_fork_and_exec.cc + posix/double_fork_and_exec.h + posix/drop_privileges.cc + posix/drop_privileges.h + posix/process_info.h + posix/symbolic_constants_posix.cc + posix/symbolic_constants_posix.h + ) +endif() + +if(APPLE) + list(APPEND UTIL_SOURCES + mac/checked_mach_address_range.h + mac/launchd.h + mac/launchd.mm + mac/mac_util.cc + mac/mac_util.h + mac/service_management.cc + mac/service_management.h + mac/xattr.cc + mac/xattr.h + mach/child_port_handshake.cc + mach/child_port_handshake.h + mach/child_port_server.cc + mach/child_port_server.h + mach/child_port_types.h + mach/composite_mach_message_server.cc + mach/composite_mach_message_server.h + mach/exc_client_variants.cc + mach/exc_client_variants.h + mach/exc_server_variants.cc + mach/exc_server_variants.h + mach/exception_behaviors.cc + mach/exception_behaviors.h + mach/exception_ports.cc + mach/exception_ports.h + mach/exception_types.cc + mach/exception_types.h + mach/mach_extensions.cc + mach/mach_extensions.h + mach/mach_message.cc + mach/mach_message.h + mach/mach_message_server.cc + mach/mach_message_server.h + mach/notify_server.cc + mach/notify_server.h + mach/scoped_task_suspend.cc + mach/scoped_task_suspend.h + mach/symbolic_constants_mach.cc + mach/symbolic_constants_mach.h + mach/task_for_pid.cc + mach/task_for_pid.h + misc/capture_context_mac.S + misc/clock_mac.cc + misc/paths_mac.cc + net/http_transport_mac.mm + posix/process_info_mac.cc + process/process_memory_mac.cc + process/process_memory_mac.h + synchronization/semaphore_mac.cc + ) +endif() + +if(LINUX OR ANDROID) + list(APPEND UTIL_SOURCES + net/http_transport_socket.cc + linux/address_types.h + linux/auxiliary_vector.cc + linux/auxiliary_vector.h + linux/checked_linux_address_range.h + linux/direct_ptrace_connection.cc + linux/direct_ptrace_connection.h + linux/exception_handler_client.cc + linux/exception_handler_client.h + linux/exception_handler_protocol.cc + linux/exception_handler_protocol.h + linux/exception_information.h + linux/memory_map.cc + linux/memory_map.h + linux/proc_stat_reader.cc + linux/proc_stat_reader.h + linux/proc_task_reader.cc + linux/proc_task_reader.h + linux/ptrace_broker.cc + linux/ptrace_broker.h + linux/ptrace_client.cc + linux/ptrace_client.h + linux/ptrace_connection.h + linux/ptracer.cc + linux/ptracer.h + linux/scoped_pr_set_dumpable.cc + linux/scoped_pr_set_dumpable.h + linux/scoped_pr_set_ptracer.cc + linux/scoped_pr_set_ptracer.h + linux/scoped_ptrace_attach.cc + linux/scoped_ptrace_attach.h + linux/socket.cc + linux/socket.h + linux/thread_info.cc + linux/thread_info.h + linux/traits.h + misc/capture_context_linux.S + misc/paths_linux.cc + posix/process_info_linux.cc + process/process_memory_linux.cc + process/process_memory_linux.h + process/process_memory_sanitized.cc + process/process_memory_sanitized.h + ) +endif() + +if(WIN32) + list(APPEND UTIL_SOURCES + file/directory_reader_win.cc + file/file_io_win.cc + file/filesystem_win.cc + misc/clock_win.cc + misc/paths_win.cc + misc/time_win.cc + net/http_transport_win.cc + process/process_memory_win.cc + process/process_memory_win.h + synchronization/semaphore_win.cc + thread/thread_win.cc + win/address_types.h + win/checked_win_address_range.h + win/command_line.cc + win/command_line.h + win/context_wrappers.h + win/critical_section_with_debug_info.cc + win/critical_section_with_debug_info.h + win/exception_handler_server.cc + win/exception_handler_server.h + win/get_function.cc + win/get_function.h + win/get_module_information.cc + win/get_module_information.h + win/handle.cc + win/handle.h + win/initial_client_data.cc + win/initial_client_data.h + win/module_version.cc + win/module_version.h + win/nt_internals.cc + win/nt_internals.h + win/ntstatus_logging.cc + win/ntstatus_logging.h + win/process_info.cc + win/process_info.h + win/process_structs.h + win/registration_protocol_win.cc + win/registration_protocol_win.h + win/safe_terminate_process.h + win/scoped_handle.cc + win/scoped_handle.h + win/scoped_local_alloc.cc + win/scoped_local_alloc.h + win/scoped_process_suspend.cc + win/scoped_process_suspend.h + win/scoped_set_event.cc + win/scoped_set_event.h + win/session_end_watcher.cc + win/session_end_watcher.h + win/termination_codes.h + win/xp_compat.h + + misc/capture_context_win.asm + win/safe_terminate_process.asm + ) +endif() + +# Copied from: https://github.com/qedsoftware/crashpad/blob/3583c50a6575857abcf140f6ea3b8d11390205b3/util/CMakeLists.txt#L196-L233 +if(APPLE) + set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") + set(input_files "") + foreach(x ${def_relative_files}) + # CMAKE_OSX_SYSROOT may be empty (e.g. for Makefile generators), + # in this case files will be taken from root. + set(full_path "${CMAKE_OSX_SYSROOT}/usr/include/mach/${x}") + if(NOT EXISTS "${full_path}") + message(FATAL_ERROR "File not found: ${full_path}") + endif() + list(APPEND input_files "${full_path}") + endforeach() + list(APPEND input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") + + find_package(PythonInterp 2.7 REQUIRED) + + set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/util/mach") + file(MAKE_DIRECTORY "${output_dir}") + + # Create generate rule for each input file. Add each generated output + # as a source to the target. + foreach(input ${input_files}) + get_filename_component(name_we "${input}" NAME_WE) + set(output_files "") + foreach(suffix "User.c" "Server.c" ".h" "Server.h") + list(APPEND output_files "${output_dir}/${name_we}${suffix}") + endforeach() + add_custom_command( + OUTPUT + ${output_files} + COMMAND + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ${output_files} + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" + ) + list(APPEND UTIL_SOURCES ${output_files}) + endforeach() + + include_directories("${CMAKE_CURRENT_BINARY_DIR}") +endif() + +add_library(crashpad_util STATIC ${UTIL_SOURCES}) +target_link_libraries(crashpad_util PUBLIC + crashpad_compat + mini_chromium +) + +target_compile_definitions(crashpad_util PUBLIC "-DZLIB_CONST") + +if(WIN32) + target_compile_definitions(crashpad_util PUBLIC "-DCRASHPAD_ZLIB_SOURCE_EMBEDDED") + target_link_libraries(crashpad_util PUBLIC zlib) +else() + target_compile_definitions(crashpad_util PUBLIC "-DCRASHPAD_ZLIB_SOURCE_SYSTEM") + target_link_libraries(crashpad_util PUBLIC "z") +endif() + +if(APPLE) + target_link_libraries(crashpad_util PUBLIC "bsm") + target_link_libraries(crashpad_util PUBLIC "-framework CoreFoundation") + target_link_libraries(crashpad_util PUBLIC "-framework Foundation") + target_link_libraries(crashpad_util PUBLIC "-framework IOKit") +endif() + +if(WIN32) + target_link_libraries(crashpad_util PUBLIC "user32" "version" "winhttp") + target_compile_options(crashpad_util PUBLIC "/wd4201") +endif() From e2dbaa7918b30301c19c3c2e4c37252e79751483 Mon Sep 17 00:00:00 2001 From: Mikhail Paulyshka Date: Fri, 20 Mar 2020 18:09:37 +0300 Subject: [PATCH 011/478] handler: set Windows subsystem to hide console window (#4) --- handler/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index b751a2ee09..abac15b14f 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -48,7 +48,11 @@ if(WIN32) ) endif() -add_executable(crashpad_handler ${HANDLER_SOURCES}) +if(WIN32) + add_executable(crashpad_handler WIN32 ${HANDLER_SOURCES}) +else() + add_executable(crashpad_handler ${HANDLER_SOURCES}) +endif() target_link_libraries(crashpad_handler crashpad_client crashpad_minidump From 5e7b7b85620c82ed3a19ca34098ad59d910b5095 Mon Sep 17 00:00:00 2001 From: Amphaal Date: Sat, 21 Mar 2020 17:31:45 +0100 Subject: [PATCH 012/478] Enable MinGW builds (#5) --- CMakeLists.txt | 22 +- client/CMakeLists.txt | 19 +- compat/CMakeLists.txt | 10 +- compat/mingw/dbghelp.h | 249 ++++++++++++++++++ compat/mingw/winnt.h | 60 +++++ handler/CMakeLists.txt | 12 +- minidump/CMakeLists.txt | 8 +- snapshot/CMakeLists.txt | 14 +- third_party/mini_chromium/CMakeLists.txt | 37 ++- .../utf_string_conversion_utils.mingw.cc | 105 ++++++++ third_party/zlib/CMakeLists.txt | 2 +- util/CMakeLists.txt | 20 +- util/misc/capture_context_win.asm | 5 +- util/stdlib/aligned_allocator.cc | 4 +- util/win/process_info.cc | 4 +- 15 files changed, 542 insertions(+), 29 deletions(-) create mode 100644 compat/mingw/dbghelp.h create mode 100644 compat/mingw/winnt.h create mode 100644 third_party/mini_chromium/utf_string_conversion_utils.mingw.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b2d6c1dc3..371960d5d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,15 @@ project(crashpad LANGUAGES C CXX) if(WIN32) enable_language(ASM_MASM) + IF(MINGW) + find_program(UASM uasm) + if(UASM) + SET(CMAKE_ASM_MASM_COMPILER "uasm") + SET(CMAKE_ASM_MASM_FLAGS "-win64 -10") + else() + message(FATAL_ERROR "UASM is required for MinGW builds ! Make sure you have it installed") + endif() + endif() else() enable_language(ASM) endif() @@ -31,8 +40,10 @@ if(ANDROID) include_directories(SYSTEM "compat/android") endif() -if(WIN32) +if(MSVC) include_directories(SYSTEM "compat/win") +elseif(MINGW) + include_directories(PUBLIC "compat/mingw") else() include_directories(PUBLIC "compat/non_win") endif() @@ -41,7 +52,7 @@ if(NOT LINUX AND NOT ANDROID) include_directories(SYSTEM "compat/non_elf") endif() -if(WIN32) +if(MSVC) add_definitions( /DNOMINMAX /DUNICODE @@ -61,6 +72,11 @@ if(WIN32) /wd4577 # 'noexcept' used with no exception handling mode specified. /wd4996 # 'X' was declared deprecated. ) +elseif(MINGW) + #redirect to wmain + add_link_options( + -municode + ) endif() add_subdirectory(client) @@ -72,7 +88,7 @@ add_subdirectory(tools) add_subdirectory(util) add_subdirectory(third_party/mini_chromium) -if(WIN32) +if(MSVC) add_subdirectory(third_party/getopt) add_subdirectory(third_party/zlib) endif() diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 940e268823..77787c13be 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -54,5 +54,22 @@ target_link_libraries(crashpad_client if(WIN32) target_link_libraries(crashpad_client "rpcrt4") - target_compile_options(crashpad_client PUBLIC "/wd4201") + if(MSVC) + target_compile_options(crashpad_client PUBLIC "/wd4201") + elseif(MINGW) + target_compile_options(crashpad_client PRIVATE + "-municode" + ) + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_client PRIVATE + "-Wno-multichar" + "-Wno-attributes" + ) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(crashpad_client PRIVATE + "-Wno-unknown-attributes" + "-Wno-unknown-pragmas" + ) + endif() endif() diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index 576bde10f3..ccf3d562cc 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -47,7 +47,7 @@ if(ANDROID) ) endif() -if(WIN32) +if(MSVC) list(APPEND COMPAT_SOURCES win/getopt.h win/strings.cc @@ -59,6 +59,11 @@ if(WIN32) win/winnt.h win/winternl.h ) +elseif(MINGW) + list(APPEND COMPAT_SOURCES + mingw/dbghelp.h + mingw/winnt.h + ) else() list(APPEND COMPAT_SOURCES non_win/dbghelp.h @@ -82,8 +87,9 @@ if(APPLE) target_sources(crashpad_compat INTERFACE ${COMPAT_SOURCES}) else() add_library(crashpad_compat STATIC ${COMPAT_SOURCES}) + set_target_properties(crashpad_compat PROPERTIES LINKER_LANGUAGE CXX) endif() -if(WIN32) +if(MSVC) target_link_libraries(crashpad_compat getopt) endif() diff --git a/compat/mingw/dbghelp.h b/compat/mingw/dbghelp.h new file mode 100644 index 0000000000..45efe1920c --- /dev/null +++ b/compat/mingw/dbghelp.h @@ -0,0 +1,249 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_COMPAT_MINGW_DBGHELP_H_ +#define CRASHPAD_COMPAT_MINGW_DBGHELP_H_ + +#include_next + +#include + +#include "base/strings/string16.h" +#include +#include +#include + +//! \file + +//! \brief Contains the state of an individual system handle at the time the +//! snapshot was taken. This structure is Windows-specific. +//! +//! \sa MINIDUMP_HANDLE_DESCRIPTOR +struct __attribute__((packed, aligned(4))) MINIDUMP_HANDLE_DESCRIPTOR_2 + : public MINIDUMP_HANDLE_DESCRIPTOR { + //! \brief An RVA to a MINIDUMP_HANDLE_OBJECT_INFORMATION structure that + //! specifies object-specific information. This member can be zero if + //! there is no extra information. + RVA ObjectInfoRva; + + //! \brief Must be zero. + uint32_t Reserved0; +}; + +//! \brief Information about XSAVE-managed state stored within CPU-specific +//! context structures. +struct __attribute__((packed, aligned(4))) XSTATE_CONFIG_FEATURE_MSC_INFO { + //! \brief The size of this structure, in bytes. This value is + //! `sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO)`. + uint32_t SizeOfInfo; + + //! \brief The size of a CPU-specific context structure carrying all XSAVE + //! state components described by this structure. + //! + //! Equivalent to the value returned by `InitializeContext()` in \a + //! ContextLength. + uint32_t ContextSize; + + //! \brief The XSAVE state-component bitmap, XSAVE_BV. + //! + //! See Intel Software Developer’s Manual, Volume 1: Basic Architecture + //! (253665-060), 13.4.2 “XSAVE Header”. + uint64_t EnabledFeatures; + + //! \brief The location of each state component within a CPU-specific context + //! structure. + //! + //! This array is indexed by bit position numbers used in #EnabledFeatures. + XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES]; +}; + +//! \anchor MINIDUMP_MISCx +//! \name MINIDUMP_MISC* +//! +//! \brief Field validity flag values for MINIDUMP_MISC_INFO::Flags1. +//! \{ + +//! \brief MINIDUMP_MISC_INFO::ProcessId is valid. +#define MINIDUMP_MISC1_PROCESS_ID 0x00000001 + +//! \brief The time-related fields in MINIDUMP_MISC_INFO are valid. +//! +//! The following fields are valid: +//! - MINIDUMP_MISC_INFO::ProcessCreateTime +//! - MINIDUMP_MISC_INFO::ProcessUserTime +//! - MINIDUMP_MISC_INFO::ProcessKernelTime +#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002 + +//! \brief The CPU-related fields in MINIDUMP_MISC_INFO_2 are valid. +//! +//! The following fields are valid: +//! - MINIDUMP_MISC_INFO_2::ProcessorMaxMhz +//! - MINIDUMP_MISC_INFO_2::ProcessorCurrentMhz +//! - MINIDUMP_MISC_INFO_2::ProcessorMhzLimit +//! - MINIDUMP_MISC_INFO_2::ProcessorMaxIdleState +//! - MINIDUMP_MISC_INFO_2::ProcessorCurrentIdleState +//! +//! \note This macro should likely have been named +//! MINIDUMP_MISC2_PROCESSOR_POWER_INFO. +#define MINIDUMP_MISC1_PROCESSOR_POWER_INFO 0x00000004 + +//! \brief MINIDUMP_MISC_INFO_3::ProcessIntegrityLevel is valid. +#define MINIDUMP_MISC3_PROCESS_INTEGRITY 0x00000010 + +//! \brief MINIDUMP_MISC_INFO_3::ProcessExecuteFlags is valid. +#define MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS 0x00000020 + +//! \brief The time zone-related fields in MINIDUMP_MISC_INFO_3 are valid. +//! +//! The following fields are valid: +//! - MINIDUMP_MISC_INFO_3::TimeZoneId +//! - MINIDUMP_MISC_INFO_3::TimeZone +#define MINIDUMP_MISC3_TIMEZONE 0x00000040 + +//! \brief MINIDUMP_MISC_INFO_3::ProtectedProcess is valid. +#define MINIDUMP_MISC3_PROTECTED_PROCESS 0x00000080 + +//! \brief The build string-related fields in MINIDUMP_MISC_INFO_4 are valid. +//! +//! The following fields are valid: +//! - MINIDUMP_MISC_INFO_4::BuildString +//! - MINIDUMP_MISC_INFO_4::DbgBldStr +#define MINIDUMP_MISC4_BUILDSTRING 0x00000100 + +//! \brief MINIDUMP_MISC_INFO_5::ProcessCookie is valid. +#define MINIDUMP_MISC5_PROCESS_COOKIE 0x00000200 + +//! \} + +//! \brief Information about the process that the minidump file contains a +//! snapshot of, as well as the system that hosted that process. +//! +//! This structure variant is used on Windows 7 (NT 6.1) and later. +//! +//! \sa \ref MINIDUMP_MISCx "MINIDUMP_MISC*" +//! \sa MINIDUMP_MISC_INFO +//! \sa MINIDUMP_MISC_INFO_2 +//! \sa MINIDUMP_MISC_INFO_4 +//! \sa MINIDUMP_MISC_INFO_5 +//! \sa MINIDUMP_MISC_INFO_N +struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_3 + : public MINIDUMP_MISC_INFO_2 { + //! \brief The process’ integrity level. + //! + //! Windows typically uses `SECURITY_MANDATORY_MEDIUM_RID` (0x2000) for + //! processes belonging to normal authenticated users and + //! `SECURITY_MANDATORY_HIGH_RID` (0x3000) for elevated processes. + //! + //! This field is Windows-specific, and has no meaning on other operating + //! systems. + uint32_t ProcessIntegrityLevel; + + //! \brief The process’ execute flags. + //! + //! On Windows, this appears to be returned by `NtQueryInformationProcess()` + //! with an argument of `ProcessExecuteFlags` (34). + //! + //! This field is Windows-specific, and has no meaning on other operating + //! systems. + uint32_t ProcessExecuteFlags; + + //! \brief Whether the process is protected. + //! + //! This field is Windows-specific, and has no meaning on other operating + //! systems. + uint32_t ProtectedProcess; + + //! \brief Whether daylight saving time was being observed in the system’s + //! location at the time of the snapshot. + //! + //! This field can contain the following values: + //! - `0` if the location does not observe daylight saving time at all. The + //! TIME_ZONE_INFORMATION::StandardName field of #TimeZoneId contains the + //! time zone name. + //! - `1` if the location observes daylight saving time, but standard time + //! was in effect at the time of the snapshot. The + //! TIME_ZONE_INFORMATION::StandardName field of #TimeZoneId contains the + //! time zone name. + //! - `2` if the location observes daylight saving time, and it was in effect + //! at the time of the snapshot. The TIME_ZONE_INFORMATION::DaylightName + //! field of #TimeZoneId contains the time zone name. + //! + //! \sa #TimeZone + uint32_t TimeZoneId; + + //! \brief Information about the time zone at the system’s location. + //! + //! \sa #TimeZoneId + TIME_ZONE_INFORMATION TimeZone; +}; + +//! \brief Information about the process that the minidump file contains a +//! snapshot of, as well as the system that hosted that process. +//! +//! This structure variant is used on Windows 8 (NT 6.2) and later. +//! +//! \sa \ref MINIDUMP_MISCx "MINIDUMP_MISC*" +//! \sa MINIDUMP_MISC_INFO +//! \sa MINIDUMP_MISC_INFO_2 +//! \sa MINIDUMP_MISC_INFO_3 +//! \sa MINIDUMP_MISC_INFO_5 +//! \sa MINIDUMP_MISC_INFO_N +struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_4 + : public MINIDUMP_MISC_INFO_3 { + //! \brief The operating system’s “build string”, a string identifying a + //! specific build of the operating system. + //! + //! This string is UTF-16-encoded and terminated by a UTF-16 `NUL` code unit. + //! + //! On Windows 8.1 (NT 6.3), this is “6.3.9600.17031 + //! (winblue_gdr.140221-1952)”. + base::char16 BuildString[260]; + + //! \brief The minidump producer’s “build string”, a string identifying the + //! module that produced a minidump file. + //! + //! This string is UTF-16-encoded and terminated by a UTF-16 `NUL` code unit. + //! + //! On Windows 8.1 (NT 6.3), this may be “dbghelp.i386,6.3.9600.16520” or + //! “dbghelp.amd64,6.3.9600.16520” depending on CPU architecture. + base::char16 DbgBldStr[40]; +}; + +//! \brief Information about the process that the minidump file contains a +//! snapshot of, as well as the system that hosted that process. +//! +//! This structure variant is used on Windows 10 and later. +//! +//! \sa \ref MINIDUMP_MISCx "MINIDUMP_MISC*" +//! \sa MINIDUMP_MISC_INFO +//! \sa MINIDUMP_MISC_INFO_2 +//! \sa MINIDUMP_MISC_INFO_3 +//! \sa MINIDUMP_MISC_INFO_4 +//! \sa MINIDUMP_MISC_INFO_N +struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_5 + : public MINIDUMP_MISC_INFO_4 { + //! \brief Information about XSAVE-managed state stored within CPU-specific + //! context structures. + //! + //! This information can be used to locate state components within + //! CPU-specific context structures. + XSTATE_CONFIG_FEATURE_MSC_INFO XStateData; + + uint32_t ProcessCookie; +}; + +//! \brief The latest known version of the MINIDUMP_MISC_INFO structure. +typedef MINIDUMP_MISC_INFO_5 MINIDUMP_MISC_INFO_N; + +#endif // CRASHPAD_COMPAT_MINGW_DBGHELP_H_ diff --git a/compat/mingw/winnt.h b/compat/mingw/winnt.h new file mode 100644 index 0000000000..268af1b3bc --- /dev/null +++ b/compat/mingw/winnt.h @@ -0,0 +1,60 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_COMPAT_MINGW_WINNT_H_ +#define CRASHPAD_COMPAT_MINGW_WINNT_H_ + +#include_next +#include + +// https://msdn.microsoft.com/library/aa373184.aspx: "Note that this structure +// definition was accidentally omitted from WinNT.h." +struct PROCESSOR_POWER_INFORMATION { + ULONG Number; + ULONG MaxMhz; + ULONG CurrentMhz; + ULONG MhzLimit; + ULONG MaxIdleState; + ULONG CurrentIdleState; +}; + +// 10.0.10240.0 SDK + +#ifndef PROCESSOR_ARCHITECTURE_ARM64 +#define PROCESSOR_ARCHITECTURE_ARM64 12 +#endif + +#ifndef PF_ARM_V8_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V8_INSTRUCTIONS_AVAILABLE 29 +#endif + +#ifndef PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE 30 +#endif + +#ifndef PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE 31 +#endif + +#ifndef PF_RDTSCP_INSTRUCTION_AVAILABLE +#define PF_RDTSCP_INSTRUCTION_AVAILABLE 32 +#endif + +// 10.0.14393.0 SDK + +#ifndef PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 +#define PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 13 +#endif + +#endif // CRASHPAD_COMPAT_MINGW_WINNT_H_ diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index abac15b14f..8b76bd39d2 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -62,6 +62,14 @@ target_link_libraries(crashpad_handler mini_chromium ) -if(WIN32) - target_compile_options(crashpad_handler PUBLIC "/wd4201") +if(WIN32) + if(MSVC) + target_compile_options(crashpad_handler PUBLIC "/wd4201") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_handler PRIVATE + "-Wno-multichar" + ) + endif() endif() + diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt index 75ab21d57c..0a2e0dda13 100644 --- a/minidump/CMakeLists.txt +++ b/minidump/CMakeLists.txt @@ -60,6 +60,12 @@ target_link_libraries(crashpad_minidump mini_chromium ) -if(WIN32) +if(MSVC) target_compile_options(crashpad_minidump PUBLIC "/wd4201" "/wd4324") endif() + +if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_minidump PRIVATE + "-Wno-multichar" + ) +endif() \ No newline at end of file diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index f349514b86..698997c1cd 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -177,5 +177,17 @@ target_link_libraries(crashpad_snapshot if(WIN32) target_link_libraries(crashpad_snapshot "powrprof") - target_compile_options(crashpad_snapshot PUBLIC "/wd4201") + if(MSVC) + target_compile_options(crashpad_snapshot PUBLIC "/wd4201") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_snapshot PRIVATE + "-Wno-multichar" + "-Wno-attributes" + ) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(crashpad_snapshot PRIVATE + "-Wno-unknown-attributes" + ) + endif() endif() diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index a2fb8d5381..c3a3245519 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -50,7 +50,6 @@ list(APPEND MINI_CHROMIUM_SOURCES strings/stringprintf.cc strings/stringprintf.h strings/sys_string_conversions.h - strings/utf_string_conversion_utils.cc strings/utf_string_conversion_utils.h strings/utf_string_conversions.cc strings/utf_string_conversions.h @@ -66,6 +65,16 @@ list(APPEND MINI_CHROMIUM_SOURCES threading/thread_local_storage.h ) +if(NOT MINGW) + list(APPEND MINI_CHROMIUM_SOURCES + strings/utf_string_conversion_utils.cc + ) +else() + list(APPEND MINI_CHROMIUM_SOURCES + ../../utf_string_conversion_utils.mingw.cc + ) +endif() + if(APPLE) list(APPEND MINI_CHROMIUM_SOURCES mac/close_nocancel.cc @@ -124,13 +133,21 @@ endif() if(WIN32) target_link_libraries(mini_chromium "advapi32" "kernel32") - target_compile_options(mini_chromium PUBLIC "/wd4201" "/wd4996") - target_compile_definitions(mini_chromium PUBLIC - NOMINMAX - UNICODE - WIN32_LEAN_AND_MEAN - _CRT_SECURE_NO_WARNINGS - _HAS_EXCEPTIONS=0 - _UNICODE - ) + if(MSVC) + target_compile_options(mini_chromium PUBLIC "/wd4201" "/wd4996") + target_compile_definitions(mini_chromium PUBLIC + NOMINMAX + UNICODE + WIN32_LEAN_AND_MEAN + _CRT_SECURE_NO_WARNINGS + _HAS_EXCEPTIONS=0 + _UNICODE + ) + elseif(MINGW) + target_compile_options(mini_chromium PRIVATE + "-municode" + "-Wno-format" + "-Wno-unknown-pragmas" + ) + endif() endif() diff --git a/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc b/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc new file mode 100644 index 0000000000..6baf7b452d --- /dev/null +++ b/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc @@ -0,0 +1,105 @@ +// Copyright 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/utf_string_conversion_utils.h" + +#include "base/third_party/icu/icu_utf.h" + +namespace base { + +bool ReadUnicodeCharacter(const char* src, + int32_t src_len, + int32_t* char_index, + uint32_t* code_point_out) { + int32_t code_point; + CBU8_NEXT(src, *char_index, src_len, code_point); + *code_point_out = static_cast(code_point); + + (*char_index)--; + + return IsValidCodepoint(code_point); +} + +bool ReadUnicodeCharacter(const char16* src, + int32_t src_len, + int32_t* char_index, + uint32_t* code_point) { + if (CBU16_IS_SURROGATE(src[*char_index])) { + if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) || + *char_index + 1 >= src_len || + !CBU16_IS_TRAIL(src[*char_index + 1])) { + return false; + } + + *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index], + src[*char_index + 1]); + (*char_index)++; + } else { + *code_point = src[*char_index]; + } + + return IsValidCodepoint(*code_point); +} + +size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) { + if (code_point <= 0x7f) { + output->push_back(static_cast(code_point)); + return 1; + } + + size_t char_offset = output->length(); + size_t original_char_offset = char_offset; + output->resize(char_offset + CBU8_MAX_LENGTH); + + CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point); + + output->resize(char_offset); + return char_offset - original_char_offset; +} + +size_t WriteUnicodeCharacter(uint32_t code_point, string16* output) { + if (CBU16_LENGTH(code_point) == 1) { + output->push_back(static_cast(code_point)); + return 1; + } + size_t char_offset = output->length(); + output->resize(char_offset + CBU16_MAX_LENGTH); + CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point); + return CBU16_MAX_LENGTH; +} + +template +void PrepareForUTF8Output(const CHAR* src, + size_t src_len, + std::string* output) { + output->clear(); + if (src_len == 0) + return; + if (src[0] < 0x80) { + output->reserve(src_len); + } else { + output->reserve(src_len * 3); + } +} + +template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*); +// template void PrepareForUTF8Output(const char16*, size_t, std::string*); + +template +void PrepareForUTF16Or32Output(const char* src, + size_t src_len, + STRING* output) { + output->clear(); + if (src_len == 0) + return; + if (static_cast(src[0]) < 0x80) { + output->reserve(src_len); + } else { + output->reserve(src_len / 2); + } +} + +template void PrepareForUTF16Or32Output(const char*, size_t, string16*); + +} // namespace base diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index d36dac5cf5..562452c9d9 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -42,7 +42,7 @@ target_compile_definitions(zlib PUBLIC HAVE_STDARG_H) include_directories(zlib) -if(WIN32) +if(MSVC) target_compile_options(zlib PUBLIC "/wd4131" # uses old-style declarator "/wd4244" # conversion from 't1' to 't2', possible loss of data diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 95e70c227c..3a796b8a67 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -284,7 +284,6 @@ if(WIN32) win/session_end_watcher.h win/termination_codes.h win/xp_compat.h - misc/capture_context_win.asm win/safe_terminate_process.asm ) @@ -340,7 +339,7 @@ target_link_libraries(crashpad_util PUBLIC target_compile_definitions(crashpad_util PUBLIC "-DZLIB_CONST") -if(WIN32) +if(MSVC) target_compile_definitions(crashpad_util PUBLIC "-DCRASHPAD_ZLIB_SOURCE_EMBEDDED") target_link_libraries(crashpad_util PUBLIC zlib) else() @@ -357,5 +356,20 @@ endif() if(WIN32) target_link_libraries(crashpad_util PUBLIC "user32" "version" "winhttp") - target_compile_options(crashpad_util PUBLIC "/wd4201") + if(MSVC) + target_compile_options(crashpad_util PUBLIC "/wd4201") + elseif(MINGW) + target_compile_options(crashpad_util PRIVATE + $<$:-municode> + ) + target_compile_definitions(crashpad_util PRIVATE + "__STDC_VERSION__=199901L" + $<$:__MINGW32__> + ) + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_util PRIVATE + $<$:-Wno-multichar> + ) + endif() endif() diff --git a/util/misc/capture_context_win.asm b/util/misc/capture_context_win.asm index b0093ba1fe..f61430d283 100644 --- a/util/misc/capture_context_win.asm +++ b/util/misc/capture_context_win.asm @@ -214,7 +214,10 @@ endif ; namespace crashpad { ; void CaptureContext(CONTEXT* context); ; } // namespace crashpad -ifdef _M_IX86 + +ifdef __MINGW32__ +CAPTURECONTEXT_SYMBOL equ _ZN8crashpad14CaptureContextEP8_CONTEXT +elseifdef _M_IX86 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPAU_CONTEXT@@@Z elseifdef _M_X64 CAPTURECONTEXT_SYMBOL equ ?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z diff --git a/util/stdlib/aligned_allocator.cc b/util/stdlib/aligned_allocator.cc index 797a3ac4f8..1cbf7d2a5f 100644 --- a/util/stdlib/aligned_allocator.cc +++ b/util/stdlib/aligned_allocator.cc @@ -18,7 +18,7 @@ #include "build/build_config.h" -#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) +#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) || defined(__MINGW32__) #include #elif defined(OS_WIN) #include @@ -31,7 +31,7 @@ namespace { // library to do so. This works even if C++ exceptions are disabled, causing // program termination if uncaught. void ThrowBadAlloc() { -#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) +#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) || defined(__MINGW32__) // This works with both libc++ and libstdc++. std::__throw_bad_alloc(); #elif defined(OS_WIN) diff --git a/util/win/process_info.cc b/util/win/process_info.cc index 49a6f27fd4..5630153964 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -115,11 +115,11 @@ bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { &bytes_read)) { // We don't have a name for the type we're reading, so include the signature // to get the type of T. - PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; + PLOG(ERROR) << "ReadProcessMemory " << FUNCTION_SIGNATURE; return false; } if (bytes_read != sizeof(T)) { - LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; + LOG(ERROR) << "ReadProcessMemory " << FUNCTION_SIGNATURE << " incorrect size"; return false; } return true; From 4ec46c337905a10f1690ef57594daa11d6e08644 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 23 Mar 2020 08:49:51 +0100 Subject: [PATCH 013/478] docs: Document MinGW changes --- README.getsentry.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.getsentry.md b/README.getsentry.md index a0af84edb4..693e96f03b 100644 --- a/README.getsentry.md +++ b/README.getsentry.md @@ -5,6 +5,7 @@ - Add `throws` declaration to `memfd_create` for compatibility with different libc versions. - Build System Changes Listed Below +- MinGW build support. # Build System Changes @@ -47,6 +48,13 @@ included files): The important thing here is to keep the list of source files in sync when updating. +## MinGW Changes + +MinGW support adds the following files which need to be kept in sync. + +- `compat/mingw/` +- `third_party/mini_chromium/utf_string_conversion_utils.mingw.cc` + # How To Update - Bump the submodules to the commit hashes specified in `./DEPS` From f71a7bbbffb618a74a4cd0088beb8c4f1dab90fa Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Wed, 1 Apr 2020 09:50:43 +0200 Subject: [PATCH 014/478] cmake: add cmake install + export (#7) --- .gitmodules | 3 + CMakeLists.txt | 156 +++++++++++++---------- client/CMakeLists.txt | 56 +++++--- compat/CMakeLists.txt | 34 ++++- crashpad-config.cmake.in | 10 ++ handler/CMakeLists.txt | 39 +++--- minidump/CMakeLists.txt | 23 ++-- snapshot/CMakeLists.txt | 40 +++--- third_party/getopt/CMakeLists.txt | 21 ++- third_party/lss/lss | 1 + third_party/mini_chromium/CMakeLists.txt | 58 ++++++--- third_party/zlib/CMakeLists.txt | 131 +++++++++++-------- tools/CMakeLists.txt | 106 ++++++++++++++- util/CMakeLists.txt | 119 ++++++++--------- 14 files changed, 530 insertions(+), 267 deletions(-) create mode 100644 crashpad-config.cmake.in create mode 160000 third_party/lss/lss diff --git a/.gitmodules b/.gitmodules index 6b27a29859..d183aa487d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "third_party/zlib/zlib"] path = third_party/zlib/zlib url = https://chromium.googlesource.com/chromium/src/third_party/zlib +[submodule "third_party/lss/lss"] + path = third_party/lss/lss + url = https://chromium.googlesource.com/linux-syscall-support diff --git a/CMakeLists.txt b/CMakeLists.txt index 371960d5d1..83bbe79de3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,47 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.10) project(crashpad LANGUAGES C CXX) +set(CRASHPAD_MAIN_PROJECT OFF) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + set(CRASHPAD_MAIN_PROJECT ON) +endif() + +option(CRASHPAD_ENABLE_INSTALL "Enable crashpad installation" "${CRASHPAD_MAIN_PROJECT}") +option(CRASHPAD_ENABLE_INSTALL_DEV "Enable crashpad development installation" "${CRASHPAD_MAIN_PROJECT}") + +if(MSVC) + set(CRASHPAD_ZLIB_SYSTEM_DEFAULT OFF) +else() + set(CRASHPAD_ZLIB_SYSTEM_DEFAULT ON) +endif() +option(CRASHPAD_ZLIB_SYSTEM "Use system zlib library" "${CRASHPAD_ZLIB_SYSTEM_DEFAULT}") + +if(CRASHPAD_ZLIB_SYSTEM) + find_package(ZLIB REQUIRED) +endif() + +include(GNUInstallDirs) +set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/crashpad") + +function(crashpad_install_target) + if(CRASHPAD_ENABLE_INSTALL) + install(TARGETS ${ARGN} EXPORT crashpad_export + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) + endif() +endfunction() +function(crashpad_install_dev) + if(CRASHPAD_ENABLE_INSTALL_DEV) + install(${ARGN}) + endif() +endfunction() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(LINUX TRUE) +endif() + if(WIN32) enable_language(ASM_MASM) IF(MINGW) @@ -9,7 +50,7 @@ if(WIN32) SET(CMAKE_ASM_MASM_COMPILER "uasm") SET(CMAKE_ASM_MASM_FLAGS "-win64 -10") else() - message(FATAL_ERROR "UASM is required for MinGW builds ! Make sure you have it installed") + message(FATAL_ERROR "UASM is required for MinGW builds! Make sure you have it installed") endif() endif() else() @@ -17,78 +58,65 @@ else() endif() set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(LINUX TRUE) -endif() +set(CMAKE_CXX_STANDARD_REQUIRED ON) -include_directories("${CMAKE_CURRENT_SOURCE_DIR}") -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third_party/mini_chromium/mini_chromium") - -# These should really be in `compat`, but we want them for the whole project -if(APPLE) - include_directories(SYSTEM "compat/mac") -else() - include_directories(PUBLIC "compat/non_mac") -endif() - -if(LINUX OR ANDROID) - include_directories(SYSTEM "compat/linux") -endif() -if(ANDROID) - include_directories(SYSTEM "compat/android") -endif() - -if(MSVC) - include_directories(SYSTEM "compat/win") -elseif(MINGW) - include_directories(PUBLIC "compat/mingw") -else() - include_directories(PUBLIC "compat/non_win") -endif() - -if(NOT LINUX AND NOT ANDROID) - include_directories(SYSTEM "compat/non_elf") -endif() +add_library(crashpad_interface INTERFACE) +target_include_directories(crashpad_interface INTERFACE + $ + $ +) +target_compile_definitions(crashpad_interface INTERFACE + CRASHPAD_LSS_SOURCE_EMBEDDED +) if(MSVC) - add_definitions( - /DNOMINMAX - /DUNICODE - /DWIN32_LEAN_AND_MEAN - /D_CRT_SECURE_NO_WARNINGS - /D_HAS_EXCEPTIONS=0 - /D_UNICODE - /FS - /W4 - /WX - /Zi - /bigobj # Support larger number of sections in obj file. - /wd4100 # Unreferenced formal parameter. - /wd4127 # Conditional expression is constant. - /wd4324 # Structure was padded due to alignment specifier. - /wd4351 # New behavior: elements of array will be default initialized. - /wd4577 # 'noexcept' used with no exception handling mode specified. - /wd4996 # 'X' was declared deprecated. + target_compile_definitions(crashpad_interface INTERFACE + NOMINMAX + UNICODE + WIN32_LEAN_AND_MEAN + _CRT_SECURE_NO_WARNINGS + _HAS_EXCEPTIONS=0 + _UNICODE ) -elseif(MINGW) - #redirect to wmain - add_link_options( - -municode + target_compile_options(crashpad_interface INTERFACE + $<$:/FS> + $<$:/W4> + $<$:/WX> + $<$:/Zi> + $<$:/bigobj> # Support larger number of sections in obj file. + $<$:/wd4100> # Unreferenced formal parameter. + $<$:/wd4127> # Conditional expression is constant. + $<$:/wd4324> # Structure was padded due to alignment specifier. + $<$:/wd4351> # New behavior: elements of array will be default initialized. + $<$:/wd4577> # 'noexcept' used with no exception handling mode specified. + $<$:/wd4996> # 'X' was declared deprecated. ) +elseif(MINGW) + # redirect to wmain + # FIXME: cmake 3.13 added target_link_options + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode") endif() +add_library(crashpad::interface ALIAS crashpad_interface) -add_subdirectory(client) add_subdirectory(compat) -add_subdirectory(handler) add_subdirectory(minidump) add_subdirectory(snapshot) -add_subdirectory(tools) add_subdirectory(util) add_subdirectory(third_party/mini_chromium) +add_subdirectory(client) -if(MSVC) - add_subdirectory(third_party/getopt) - add_subdirectory(third_party/zlib) -endif() +add_subdirectory(third_party/zlib) +add_subdirectory(third_party/getopt) + +add_subdirectory(tools) +add_subdirectory(handler) + +if(CRASHPAD_ENABLE_INSTALL_DEV) + install(EXPORT crashpad_export NAMESPACE crashpad:: FILE crashpad-targets.cmake + DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") + include(CMakePackageConfigHelpers) + configure_package_config_file(crashpad-config.cmake.in crashpad-config.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" + ) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crashpad-config.cmake" DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") +endif() \ No newline at end of file diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 77787c13be..57d10a9eb8 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND CLIENT_SOURCES +add_library(crashpad_client STATIC annotation.cc annotation.h annotation_list.cc @@ -18,7 +18,7 @@ list(APPEND CLIENT_SOURCES ) if(APPLE) - list(APPEND CLIENT_SOURCES + target_sources(crashpad_client PRIVATE crash_report_database_mac.mm crashpad_client_mac.cc simulate_crash_mac.cc @@ -27,37 +27,47 @@ if(APPLE) endif() if(LINUX OR ANDROID) - list(APPEND CLIENT_SOURCES - crashpad_client_linux.cc - simulate_crash_linux.h - client_argv_handling.cc - client_argv_handling.h - crashpad_info_note.S - crash_report_database_generic.cc + target_sources(crashpad_client PRIVATE + crashpad_client_linux.cc + simulate_crash_linux.h + client_argv_handling.cc + client_argv_handling.h + crashpad_info_note.S + crash_report_database_generic.cc ) endif() if(WIN32) - list(APPEND CLIENT_SOURCES - crash_report_database_win.cc - crashpad_client_win.cc - simulate_crash_win.h + target_sources(crashpad_client PRIVATE + crash_report_database_win.cc + crashpad_client_win.cc + simulate_crash_win.h ) endif() -add_library(crashpad_client STATIC ${CLIENT_SOURCES}) +target_include_directories(crashpad_client INTERFACE + "$" + "$" +) target_link_libraries(crashpad_client - crashpad_compat - crashpad_util - mini_chromium + PRIVATE + $ + PUBLIC + crashpad_compat + crashpad_util + mini_chromium ) +target_compile_features(crashpad_client PUBLIC cxx_std_14) + +set_property(TARGET crashpad_client PROPERTY EXPORT_NAME client) +add_library(crashpad::client ALIAS crashpad_client) if(WIN32) - target_link_libraries(crashpad_client "rpcrt4") + target_link_libraries(crashpad_client PRIVATE rpcrt4) if(MSVC) - target_compile_options(crashpad_client PUBLIC "/wd4201") + target_compile_options(crashpad_client PRIVATE "/wd4201") elseif(MINGW) - target_compile_options(crashpad_client PRIVATE + target_compile_options(crashpad_client PUBLIC "-municode" ) endif() @@ -73,3 +83,9 @@ if(WIN32) ) endif() endif() + +crashpad_install_target(crashpad_client) +crashpad_install_dev(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/client" + FILES_MATCHING PATTERN "*.h" +) diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index ccf3d562cc..860a6e0731 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND COMPAT_SOURCES "") +set(COMPAT_SOURCES) if(APPLE) list(APPEND COMPAT_SOURCES @@ -83,13 +83,39 @@ endif() if(APPLE) add_library(crashpad_compat INTERFACE) - list(TRANSFORM COMPAT_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") - target_sources(crashpad_compat INTERFACE ${COMPAT_SOURCES}) + set(TI_TYPE "INTERFACE") else() add_library(crashpad_compat STATIC ${COMPAT_SOURCES}) set_target_properties(crashpad_compat PROPERTIES LINKER_LANGUAGE CXX) + set(TI_TYPE "PUBLIC") + target_link_libraries(crashpad_compat PRIVATE + $ + ) endif() if(MSVC) - target_link_libraries(crashpad_compat getopt) + target_include_directories(crashpad_compat ${TI_TYPE} "$") +elseif(MINGW) + target_include_directories(crashpad_compat ${TI_TYPE} "$") +else() + target_include_directories(crashpad_compat ${TI_TYPE} "$") +endif() + +if(APPLE) + target_include_directories(crashpad_compat ${TI_TYPE} "$") +else() + target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() + +if(LINUX OR ANDROID) + target_include_directories(crashpad_compat ${TI_YPE} "$") +endif() + +if(ANDROID) + target_include_directories(crashpad_compat ${TI_YPE} "$") +endif() + +set_property(TARGET crashpad_compat PROPERTY EXPORT_NAME compat) +add_library(crashpad::compat ALIAS crashpad_compat) + +crashpad_install_target(crashpad_compat) diff --git a/crashpad-config.cmake.in b/crashpad-config.cmake.in new file mode 100644 index 0000000000..846797d774 --- /dev/null +++ b/crashpad-config.cmake.in @@ -0,0 +1,10 @@ +include("${CMAKE_CURRENT_LIST_DIR}/crashpad-targets.cmake") + +if(@CRASHPAD_ZLIB_SYSTEM@) + find_package(ZLIB REQUIRED) + target_include_directories(crashpad::zlib INTERFACE ${ZLIB_INCLUDE_DIRS}) + target_compile_definitions(crashpad::zlib INTERFACE ${ZLIB_COMPILE_DEFINITIONS}) + target_link_libraries(crashpad::zlib INTERFACE ${ZLIB_LIBRARIES}) +endif() + +@PACKAGE_INIT@ diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 8b76bd39d2..3d9dbe4dc1 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND HANDLER_SOURCES +add_executable(crashpad_handler WIN32 main.cc crash_report_upload_thread.cc crash_report_upload_thread.h @@ -13,7 +13,7 @@ list(APPEND HANDLER_SOURCES ) if(APPLE) - list(APPEND HANDLER_SOURCES + target_sources(crashpad_handler PRIVATE mac/crash_report_exception_handler.cc mac/crash_report_exception_handler.h mac/exception_handler_server.cc @@ -24,7 +24,7 @@ if(APPLE) endif() if(LINUX OR ANDROID) - list(APPEND HANDLER_SOURCES + target_sources(crashpad_handler PRIVATE linux/capture_snapshot.cc linux/capture_snapshot.h linux/crash_report_exception_handler.cc @@ -35,36 +35,35 @@ if(LINUX OR ANDROID) endif() if(LINUX) - list(APPEND HANDLER_SOURCES + target_sources(crashpad_handler PRIVATE linux/cros_crash_report_exception_handler.cc linux/cros_crash_report_exception_handler.h ) endif() if(WIN32) - list(APPEND HANDLER_SOURCES + target_sources(crashpad_handler PRIVATE win/crash_report_exception_handler.cc win/crash_report_exception_handler.h ) endif() -if(WIN32) - add_executable(crashpad_handler WIN32 ${HANDLER_SOURCES}) -else() - add_executable(crashpad_handler ${HANDLER_SOURCES}) -endif() target_link_libraries(crashpad_handler - crashpad_client - crashpad_minidump - crashpad_snapshot - crashpad_tools - crashpad_util - mini_chromium + PRIVATE + $ + PUBLIC + crashpad_client + crashpad_getopt + crashpad_minidump + crashpad_snapshot + crashpad_tools + crashpad_util + mini_chromium ) if(WIN32) if(MSVC) - target_compile_options(crashpad_handler PUBLIC "/wd4201") + target_compile_options(crashpad_handler PRIVATE "/wd4201") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_handler PRIVATE @@ -73,3 +72,9 @@ if(WIN32) endif() endif() +set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME handler) +add_executable(crashpad::handler ALIAS crashpad_handler) + +install(TARGETS crashpad_handler EXPORT crashpad_export + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" +) diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt index 0a2e0dda13..83ed22f121 100644 --- a/minidump/CMakeLists.txt +++ b/minidump/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND MINIDUMP_SOURCES +add_library(crashpad_minidump STATIC minidump_annotation_writer.cc minidump_annotation_writer.h minidump_byte_array_writer.cc @@ -52,20 +52,27 @@ list(APPEND MINIDUMP_SOURCES minidump_writer_util.h ) -add_library(crashpad_minidump STATIC ${MINIDUMP_SOURCES}) target_link_libraries(crashpad_minidump - crashpad_compat - crashpad_snapshot - crashpad_util - mini_chromium + PRIVATE + $ + PUBLIC + crashpad_compat + crashpad_snapshot + crashpad_util + mini_chromium ) if(MSVC) - target_compile_options(crashpad_minidump PUBLIC "/wd4201" "/wd4324") + target_compile_options(crashpad_minidump PRIVATE "/wd4201" "/wd4324") endif() if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_minidump PRIVATE "-Wno-multichar" ) -endif() \ No newline at end of file +endif() + +set_property(TARGET crashpad_minidump PROPERTY EXPORT_NAME minidump) +add_library(crashpad::minidump ALIAS crashpad_minidump) + +crashpad_install_target(crashpad_minidump) diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 698997c1cd..4bbd757676 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND SNAPSHOT_SOURCES +add_library(crashpad_snapshot STATIC annotation_snapshot.cc annotation_snapshot.h capture_memory.cc @@ -48,7 +48,7 @@ list(APPEND SNAPSHOT_SOURCES if(APPLE) - list(APPEND SNAPSHOT_SOURCES + target_sources(crashpad_snapshot PRIVATE posix/timezone.cc posix/timezone.h mac/cpu_context_mac.cc @@ -81,14 +81,14 @@ if(APPLE) mac/thread_snapshot_mac.h ) else() - list(APPEND SNAPSHOT_SOURCES + target_sources(crashpad_snapshot PRIVATE crashpad_types/crashpad_info_reader.cc crashpad_types/crashpad_info_reader.h ) endif() if(LINUX OR ANDROID) - list(APPEND SNAPSHOT_SOURCES + target_sources(crashpad_snapshot PRIVATE posix/timezone.cc posix/timezone.h linux/cpu_context_linux.cc @@ -130,7 +130,7 @@ if(LINUX OR ANDROID) endif() if(WIN32) - list(APPEND SNAPSHOT_SOURCES + target_sources(crashpad_snapshot PRIVATE win/capture_memory_delegate_win.cc win/capture_memory_delegate_win.h win/cpu_context_win.cc @@ -160,25 +160,30 @@ if(WIN32) ) endif() -# TODO: if(x86) - list(APPEND SNAPSHOT_SOURCES +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(x86)|(i[3-7]86)") + target_sources(crashpad_snapshot PRIVATE x86/cpuid_reader.cc x86/cpuid_reader.h ) -#endif() +endif() -add_library(crashpad_snapshot STATIC ${SNAPSHOT_SOURCES}) +target_include_directories(crashpad_snapshot INTERFACE + "$" +) target_link_libraries(crashpad_snapshot - crashpad_client - crashpad_compat - crashpad_util - mini_chromium + PRIVATE + $ + PUBLIC + crashpad_client + crashpad_compat + crashpad_util + mini_chromium ) if(WIN32) - target_link_libraries(crashpad_snapshot "powrprof") + target_link_libraries(crashpad_snapshot PRIVATE powrprof) if(MSVC) - target_compile_options(crashpad_snapshot PUBLIC "/wd4201") + target_compile_options(crashpad_snapshot PRIVATE "/wd4201") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_snapshot PRIVATE @@ -191,3 +196,8 @@ if(WIN32) ) endif() endif() + +set_property(TARGET crashpad_snapshot PROPERTY EXPORT_NAME snapshot) +add_library(crashpad::snapshot ALIAS crashpad_snapshot) + +crashpad_install_target(crashpad_snapshot) diff --git a/third_party/getopt/CMakeLists.txt b/third_party/getopt/CMakeLists.txt index 7671ca0416..91dd2ff56e 100644 --- a/third_party/getopt/CMakeLists.txt +++ b/third_party/getopt/CMakeLists.txt @@ -1,6 +1,17 @@ -list(APPEND GETOPT_SOURCES - getopt.cc - getopt.h -) +if(MSVC) + add_library(crashpad_getopt STATIC + getopt.cc + getopt.h + ) + target_include_directories(crashpad_getopt PUBLIC + $ + ) + target_link_libraries(crashpad_getopt PRIVATE + $ + ) +else() + add_library(crashpad_getopt INTERFACE) +endif() -add_library(getopt STATIC ${GETOPT_SOURCES}) +set_property(TARGET crashpad_getopt PROPERTY EXPORT_NAME getopt) +add_library(crashpad::getopt ALIAS crashpad_getopt) diff --git a/third_party/lss/lss b/third_party/lss/lss new file mode 160000 index 0000000000..fd00dbbd0c --- /dev/null +++ b/third_party/lss/lss @@ -0,0 +1 @@ +Subproject commit fd00dbbd0c06a309c657d89e9430143b179ff6db diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index c3a3245519..341107a055 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -1,4 +1,10 @@ -list(APPEND MINI_CHROMIUM_SOURCES +add_library(mini_chromium STATIC) +function(mc_append_sources) + list(TRANSFORM ARGN PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/mini_chromium/base/") + target_sources(mini_chromium PRIVATE ${ARGN}) +endfunction() + +mc_append_sources( ../build/build_config.h atomicops.h atomicops_internals_atomicword_compat.h @@ -66,17 +72,17 @@ list(APPEND MINI_CHROMIUM_SOURCES ) if(NOT MINGW) - list(APPEND MINI_CHROMIUM_SOURCES + mc_append_sources( strings/utf_string_conversion_utils.cc ) else() - list(APPEND MINI_CHROMIUM_SOURCES - ../../utf_string_conversion_utils.mingw.cc + mc_append_sources( + ${CMAKE_CURRENT_SOURCE_DIR}/../../utf_string_conversion_utils.mingw.cc ) endif() if(APPLE) - list(APPEND MINI_CHROMIUM_SOURCES + mc_append_sources( mac/close_nocancel.cc mac/foundation_util.h mac/foundation_util.mm @@ -98,7 +104,7 @@ if(APPLE) endif() if(WIN32) - list(APPEND MINI_CHROMIUM_SOURCES + mc_append_sources( process/process_metrics_win.cc strings/string_util_win.cc strings/string_util_win.h @@ -106,7 +112,7 @@ if(WIN32) threading/thread_local_storage_win.cc ) else() - list(APPEND MINI_CHROMIUM_SOURCES + mc_append_sources( files/file_util_posix.cc posix/eintr_wrapper.h posix/safe_strerror.cc @@ -119,23 +125,29 @@ else() ) endif() -list(TRANSFORM MINI_CHROMIUM_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/mini_chromium/base/") - -add_library(mini_chromium STATIC ${MINI_CHROMIUM_SOURCES}) - if(APPLE) - target_link_libraries(mini_chromium PUBLIC "-framework ApplicationServices") - target_link_libraries(mini_chromium PUBLIC "-framework CoreFoundation") - target_link_libraries(mini_chromium PUBLIC "-framework Foundation") - target_link_libraries(mini_chromium PUBLIC "-framework IOKit") - target_link_libraries(mini_chromium PUBLIC "-framework Security") + target_link_libraries(mini_chromium PUBLIC + "-framework ApplicationServices" + "-framework CoreFoundation" + "-framework Foundation" + "-framework IOKit" + "-framework Security" + ) endif() +target_include_directories(mini_chromium PUBLIC + "$" + $ +) +target_link_libraries(mini_chromium + PRIVATE + $ +) if(WIN32) - target_link_libraries(mini_chromium "advapi32" "kernel32") + target_link_libraries(mini_chromium PRIVATE advapi32 kernel32) if(MSVC) - target_compile_options(mini_chromium PUBLIC "/wd4201" "/wd4996") - target_compile_definitions(mini_chromium PUBLIC + target_compile_options(mini_chromium PRIVATE "/wd4201" "/wd4996") + target_compile_definitions(mini_chromium PRIVATE NOMINMAX UNICODE WIN32_LEAN_AND_MEAN @@ -151,3 +163,11 @@ if(WIN32) ) endif() endif() + +add_library(crashpad::mini_chromium ALIAS mini_chromium) + +crashpad_install_target(mini_chromium) +crashpad_install_dev(DIRECTORY mini_chromium + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad" + FILES_MATCHING PATTERN "*.h" +) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index 562452c9d9..7ed2f58680 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -1,54 +1,83 @@ -list(APPEND ZLIB_SOURCES - zlib/adler32.c - zlib/compress.c - zlib/crc32.c - zlib/crc32.h - zlib/deflate.c - zlib/deflate.h - zlib/gzclose.c - zlib/gzguts.h - zlib/gzlib.c - zlib/gzread.c - zlib/gzwrite.c - zlib/infback.c - zlib/inffast.c - zlib/inffast.h - zlib/inffixed.h - zlib/inflate.c - zlib/inflate.h - zlib/inftrees.c - zlib/inftrees.h - zlib/names.h - zlib/trees.c - zlib/trees.h - zlib/uncompr.c - zlib/zconf.h - zlib/zlib.h - zlib/zutil.c - zlib/zutil.h - zlib_crashpad.h -) - -# TODO: x86/x64 -list(APPEND ZLIB_SOURCES - zlib/crc_folding.c - zlib/fill_window_sse.c - zlib/x86.c - zlib/x86.h -) +if(CRASHPAD_ZLIB_SYSTEM) + add_library(crashpad_zlib INTERFACE) + string(REPLACE ";" "$" GENEX_ZLIB_LIBRARIES "${ZLIB_LIBRARIES}") + target_include_directories(crashpad_zlib INTERFACE + $ + ) + target_compile_definitions(crashpad_zlib INTERFACE + ZLIB_CONST + CRASHPAD_ZLIB_SOURCE_SYSTEM + $ + ) + target_link_libraries(crashpad_zlib INTERFACE $) +else() + add_library(crashpad_zlib STATIC + zlib/adler32.c + zlib/compress.c + zlib/crc32.c + zlib/crc32.h + zlib/deflate.c + zlib/deflate.h + zlib/gzclose.c + zlib/gzguts.h + zlib/gzlib.c + zlib/gzread.c + zlib/gzwrite.c + zlib/infback.c + zlib/inffast.c + zlib/inffast.h + zlib/inffixed.h + zlib/inflate.c + zlib/inflate.h + zlib/inftrees.c + zlib/inftrees.h + zlib/names.h + zlib/trees.c + zlib/trees.h + zlib/uncompr.c + zlib/zconf.h + zlib/zlib.h + zlib/zutil.c + zlib/zutil.h + zlib_crashpad.h + ) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(x86)|(i[3-7]86)|(AMD64)") + target_sources(crashpad_zlib PRIVATE + zlib/crc_folding.c + zlib/fill_window_sse.c + zlib/x86.c + zlib/x86.h + ) + endif() + target_compile_definitions(crashpad_zlib PUBLIC + CRASHPAD_ZLIB_SOURCE_EMBEDDED + ) + target_compile_definitions(crashpad_zlib + PUBLIC + ZLIB_CONST + PRIVATE + HAVE_STDARG_H + ) + target_include_directories(crashpad_zlib PRIVATE + "$" + ) + target_link_libraries(crashpad_zlib PRIVATE + $ + ) -add_library(zlib STATIC ${ZLIB_SOURCES}) -target_compile_definitions(zlib PUBLIC HAVE_STDARG_H) + if(MSVC) + target_compile_options(crashpad_zlib PRIVATE + "/wd4131" # uses old-style declarator + "/wd4244" # conversion from 't1' to 't2', possible loss of data + "/wd4245" # conversion from 't1' to 't2', signed/unsigned mismatch + "/wd4267" # conversion from 'size_t' to 't', possible loss of data + "/wd4324" # structure was padded due to alignment specifier + "/wd4702" # unreachable code + ) + endif() +endif() -include_directories(zlib) +set_property(TARGET crashpad_zlib PROPERTY EXPORT_NAME zlib) +add_library(crashpad::zlib ALIAS crashpad_zlib) -if(MSVC) - target_compile_options(zlib PUBLIC - "/wd4131" # uses old-style declarator - "/wd4244" # conversion from 't1' to 't2', possible loss of data - "/wd4245" # conversion from 't1' to 't2', signed/unsigned mismatch - "/wd4267" # conversion from 'size_t' to 't', possible loss of data - "/wd4324" # structure was padded due to alignment specifier - "/wd4702" # unreachable code - ) -endif() +crashpad_install_target(crashpad_zlib) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f72f7e6e81..5ad79d5d5e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,11 +1,105 @@ -list(APPEND TOOLS_SOURCES +add_library(crashpad_tools STATIC tool_support.cc tool_support.h ) - -add_library(crashpad_tools STATIC ${TOOLS_SOURCES}) -target_link_libraries(crashpad_tools - mini_chromium +target_link_libraries(crashpad_tools PRIVATE + $ ) -# TODO: do we need any tool executables? +set_property(TARGET crashpad_tools PROPERTY EXPORT_NAME tools) +add_library(crashpad::tools ALIAS crashpad_tools) + +crashpad_install_target(crashpad_tools) + +if(CRASHPAD_BUILD_TOOLS) + add_executable(crashpad_database_util + crashpad_database_util.cc + ) + target_link_libraries(crashpad_database_util PRIVATE + crashpad_client + crashpad_compat + crashpad_getopt + crashpad_tools + ) + crashpad_install_target(crashpad_database_util) + + add_executable(crashpad_http_upload + crashpad_http_upload.cc + ) + target_link_libraries(crashpad_http_upload PRIVATE + crashpad_client + crashpad_compat + crashpad_getopt + crashpad_tools + crashpad_zlib + mini_chromium + ) + crashpad_install_target(crashpad_http_upload) + + add_executable(crashpad_generate_dump + generate_dump.cc + ) + target_link_libraries(crashpad_generate_dump PRIVATE + crashpad_getopt + crashpad_minidump + crashpad_snapshot + crashpad_tools + mini_chromium + ) + if(APPLE) + # FIXME: cmake 3.13 added target_link_options + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sectcreate __TEXT __info_plist \"${CMAKE_CURRENT_SOURCE_DIR}/mac/sectaskaccess_info.plist\"") + endif() + crashpad_install_target(crashpad_generate_dump) + + if(APPLE) + add_executable(run_with_crashpad + run_with_crashpad.cc + ) + target_link_libraries(run_with_crashpad PRIVATE + crashpad_client + crashpad_compat + crashpad_tools + crashpad_util + mini_chromium + ) + crashpad_install_target(run_with_crashpad) + + add_executable(catch_exception_tool + mac/catch_exception_tool.cc + ) + target_link_libraries(catch_exception_tool PRIVATE + crashpad_compat + crashpad_tools + crashpad_util + mini_chromium + ) + crashpad_install_target(catch_exception_tool) + + add_executable(exception_port_tool + mac/exception_port_tool.cc + ) + target_link_libraries(exception_port_tool PRIVATE + crashpad_compat + crashpad_tools + crashpad_util + mini_chromium + ) + # FIXME: cmake 3.13 added target_link_options + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sectcreate __TEXT __info_plist \"${CMAKE_CURRENT_SOURCE_DIR}/mac/sectaskaccess_info.plist\"") + crashpad_install_target(exception_port_tool) + + add_executable(on_demand_service_tool + mac/on_demand_service_tool.mm + ) + target_link_libraries(on_demand_service_tool PRIVATE + -framework CoreFoundation + -framework Foundation + crashpad_compat + crashpad_tools + crashpad_util + mini_chromium + ) + crashpad_install_target(on_demand_service_tool) + endif() +endif() diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 3a796b8a67..523bfe792d 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND UTIL_SOURCES +add_library(crashpad_util STATIC file/delimited_file_reader.cc file/delimited_file_reader.h file/directory_reader.h @@ -102,7 +102,7 @@ list(APPEND UTIL_SOURCES ) if(NOT WIN32) - list(APPEND UTIL_SOURCES + target_sources(crashpad_util PRIVATE file/directory_reader_posix.cc file/file_io_posix.cc file/filesystem_posix.cc @@ -130,7 +130,7 @@ if(NOT WIN32) endif() if(APPLE) - list(APPEND UTIL_SOURCES + target_sources(crashpad_util PRIVATE mac/checked_mach_address_range.h mac/launchd.h mac/launchd.mm @@ -183,7 +183,7 @@ if(APPLE) endif() if(LINUX OR ANDROID) - list(APPEND UTIL_SOURCES + target_sources(crashpad_util PRIVATE net/http_transport_socket.cc linux/address_types.h linux/auxiliary_vector.cc @@ -231,7 +231,7 @@ if(LINUX OR ANDROID) endif() if(WIN32) - list(APPEND UTIL_SOURCES + target_sources(crashpad_util PRIVATE file/directory_reader_win.cc file/file_io_win.cc file/filesystem_win.cc @@ -291,73 +291,71 @@ endif() # Copied from: https://github.com/qedsoftware/crashpad/blob/3583c50a6575857abcf140f6ea3b8d11390205b3/util/CMakeLists.txt#L196-L233 if(APPLE) - set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") - set(input_files "") - foreach(x ${def_relative_files}) - # CMAKE_OSX_SYSROOT may be empty (e.g. for Makefile generators), - # in this case files will be taken from root. - set(full_path "${CMAKE_OSX_SYSROOT}/usr/include/mach/${x}") - if(NOT EXISTS "${full_path}") - message(FATAL_ERROR "File not found: ${full_path}") - endif() - list(APPEND input_files "${full_path}") - endforeach() - list(APPEND input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") + set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") + set(input_files "") + foreach(x ${def_relative_files}) + # CMAKE_OSX_SYSROOT may be empty (e.g. for Makefile generators), + # in this case files will be taken from root. + set(full_path "${CMAKE_OSX_SYSROOT}/usr/include/mach/${x}") + if(NOT EXISTS "${full_path}") + message(FATAL_ERROR "File not found: ${full_path}") + endif() + list(APPEND input_files "${full_path}") + endforeach() + list(APPEND input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") - find_package(PythonInterp 2.7 REQUIRED) + find_package(PythonInterp 2.7 REQUIRED) - set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/util/mach") - file(MAKE_DIRECTORY "${output_dir}") + set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/util/mach") + file(MAKE_DIRECTORY "${output_dir}") - # Create generate rule for each input file. Add each generated output - # as a source to the target. - foreach(input ${input_files}) - get_filename_component(name_we "${input}" NAME_WE) - set(output_files "") - foreach(suffix "User.c" "Server.c" ".h" "Server.h") - list(APPEND output_files "${output_dir}/${name_we}${suffix}") + # Create generate rule for each input file. Add each generated output + # as a source to the target. + foreach(input ${input_files}) + get_filename_component(name_we "${input}" NAME_WE) + set(output_files "") + foreach(suffix "User.c" "Server.c" ".h" "Server.h") + list(APPEND output_files "${output_dir}/${name_we}${suffix}") + endforeach() + add_custom_command( + OUTPUT + ${output_files} + COMMAND + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ${output_files} + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" + ) + target_sources(crashpad_util PRIVATE ${output_files}) endforeach() - add_custom_command( - OUTPUT - ${output_files} - COMMAND - "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ${output_files} - DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" - ) - list(APPEND UTIL_SOURCES ${output_files}) - endforeach() - include_directories("${CMAKE_CURRENT_BINARY_DIR}") + include_directories("${CMAKE_CURRENT_BINARY_DIR}") endif() -add_library(crashpad_util STATIC ${UTIL_SOURCES}) -target_link_libraries(crashpad_util PUBLIC - crashpad_compat - mini_chromium +target_include_directories(crashpad_util PRIVATE + $ +) +target_link_libraries(crashpad_util + PRIVATE + $ + PUBLIC + crashpad_compat + crashpad_zlib + mini_chromium ) - -target_compile_definitions(crashpad_util PUBLIC "-DZLIB_CONST") - -if(MSVC) - target_compile_definitions(crashpad_util PUBLIC "-DCRASHPAD_ZLIB_SOURCE_EMBEDDED") - target_link_libraries(crashpad_util PUBLIC zlib) -else() - target_compile_definitions(crashpad_util PUBLIC "-DCRASHPAD_ZLIB_SOURCE_SYSTEM") - target_link_libraries(crashpad_util PUBLIC "z") -endif() if(APPLE) - target_link_libraries(crashpad_util PUBLIC "bsm") - target_link_libraries(crashpad_util PUBLIC "-framework CoreFoundation") - target_link_libraries(crashpad_util PUBLIC "-framework Foundation") - target_link_libraries(crashpad_util PUBLIC "-framework IOKit") + target_link_libraries(crashpad_util PRIVATE + bsm + "-framework CoreFoundation" + "-framework Foundation" + "-framework IOKit" + ) endif() if(WIN32) - target_link_libraries(crashpad_util PUBLIC "user32" "version" "winhttp") + target_link_libraries(crashpad_util PRIVATE user32 version winhttp) if(MSVC) - target_compile_options(crashpad_util PUBLIC "/wd4201") + target_compile_options(crashpad_util PRIVATE "/wd4201") elseif(MINGW) target_compile_options(crashpad_util PRIVATE $<$:-municode> @@ -373,3 +371,8 @@ if(WIN32) ) endif() endif() + +set_property(TARGET crashpad_util PROPERTY EXPORT_NAME util) +add_library(crashpad::util ALIAS crashpad_util) + +crashpad_install_target(crashpad_util) From 23474e346aa7c24a27506ee038b22bae74a5ce75 Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Wed, 1 Apr 2020 00:53:05 -0700 Subject: [PATCH 015/478] win: Make crashpad_handler a GUI app (#6) This change adds a missing `/SUBSYSTEM:WINDOWS` option to the linker command line on Windows for the `crashpad_handler.exe` binary. Without this option (which the regular Crashpad build system [also adds](https://github.com/getsentry/crashpad/blob/getsentry/handler/handler.gyp#L90)) the resulting executable will open an empty console window on startup, which is particularly unsightly for Windows GUI applications integrating `sentry-native` which would otherwise have no console windows. --- handler/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 3d9dbe4dc1..f9d23b6949 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -64,6 +64,7 @@ target_link_libraries(crashpad_handler if(WIN32) if(MSVC) target_compile_options(crashpad_handler PRIVATE "/wd4201") + target_link_options(crashpad_handler PRIVATE "/SUBSYSTEM:WINDOWS") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_handler PRIVATE From 3da8bcf64b01e32a84385b042e707b2561827a68 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Wed, 8 Apr 2020 22:06:51 +0200 Subject: [PATCH 016/478] build(cmake): remove /W3 from CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (#8) --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83bbe79de3..56a885b1dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,8 @@ if(MSVC) _HAS_EXCEPTIONS=0 _UNICODE ) + string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") target_compile_options(crashpad_interface INTERFACE $<$:/FS> $<$:/W4> @@ -119,4 +121,4 @@ if(CRASHPAD_ENABLE_INSTALL_DEV) INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/crashpad-config.cmake" DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") -endif() \ No newline at end of file +endif() From f8c8a966ea9fc8f5cfc140f8c9520d1692b85488 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 9 Apr 2020 18:55:02 +0200 Subject: [PATCH 017/478] build(cmake): use CMAKE_CXX_FLAGS as source of regex for CMAKE_CXX_FLAGS (#9) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56a885b1dd..6b4d207e49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ if(MSVC) _UNICODE ) string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") target_compile_options(crashpad_interface INTERFACE $<$:/FS> $<$:/W4> From 2f362fea4cff4bd51e14125db55dc1dca15b8631 Mon Sep 17 00:00:00 2001 From: Amphaal Date: Fri, 10 Apr 2020 11:17:27 +0200 Subject: [PATCH 018/478] build: Enhance MinGW compatibility for cross compilation (#10) --- CMakeLists.txt | 14 +++++++------- third_party/mini_chromium/CMakeLists.txt | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b4d207e49..dfe31311a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,13 +44,13 @@ endif() if(WIN32) enable_language(ASM_MASM) - IF(MINGW) - find_program(UASM uasm) - if(UASM) - SET(CMAKE_ASM_MASM_COMPILER "uasm") - SET(CMAKE_ASM_MASM_FLAGS "-win64 -10") - else() - message(FATAL_ERROR "UASM is required for MinGW builds! Make sure you have it installed") + if(MINGW) + if(NOT CMAKE_ASM_MASM_COMPILER OR CMAKE_ASM_MASM_COMPILER STREQUAL "ml" OR CMAKE_ASM_MASM_COMPILER STREQUAL "ml64") + message(WARNING "No custom ASM_MASM compiler defined via 'CMAKE_ASM_MASM_COMPILER'. Trying to use UASM...") + set(CMAKE_ASM_MASM_COMPILER "uasm") + endif() + if(NOT CMAKE_ASM_MASM_FLAGS) + set(CMAKE_ASM_MASM_FLAGS "-win64 -10") #use default compatibility flags endif() endif() else() diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 341107a055..8cdff52175 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -77,7 +77,7 @@ if(NOT MINGW) ) else() mc_append_sources( - ${CMAKE_CURRENT_SOURCE_DIR}/../../utf_string_conversion_utils.mingw.cc + ../../utf_string_conversion_utils.mingw.cc ) endif() From 944c775539da90dd5dd65401b6aabb0a0159f94a Mon Sep 17 00:00:00 2001 From: Amphaal Date: Tue, 14 Apr 2020 08:41:40 +0200 Subject: [PATCH 019/478] build: MinGW dbghelp.h C-compatible (#11) --- compat/mingw/dbghelp.h | 127 ++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 21 deletions(-) diff --git a/compat/mingw/dbghelp.h b/compat/mingw/dbghelp.h index 45efe1920c..b492198485 100644 --- a/compat/mingw/dbghelp.h +++ b/compat/mingw/dbghelp.h @@ -15,32 +15,17 @@ #ifndef CRASHPAD_COMPAT_MINGW_DBGHELP_H_ #define CRASHPAD_COMPAT_MINGW_DBGHELP_H_ -#include_next +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-include-next" +#include_next #include - -#include "base/strings/string16.h" #include -#include #include +#include //! \file -//! \brief Contains the state of an individual system handle at the time the -//! snapshot was taken. This structure is Windows-specific. -//! -//! \sa MINIDUMP_HANDLE_DESCRIPTOR -struct __attribute__((packed, aligned(4))) MINIDUMP_HANDLE_DESCRIPTOR_2 - : public MINIDUMP_HANDLE_DESCRIPTOR { - //! \brief An RVA to a MINIDUMP_HANDLE_OBJECT_INFORMATION structure that - //! specifies object-specific information. This member can be zero if - //! there is no extra information. - RVA ObjectInfoRva; - - //! \brief Must be zero. - uint32_t Reserved0; -}; - //! \brief Information about XSAVE-managed state stored within CPU-specific //! context structures. struct __attribute__((packed, aligned(4))) XSTATE_CONFIG_FEATURE_MSC_INFO { @@ -126,6 +111,23 @@ struct __attribute__((packed, aligned(4))) XSTATE_CONFIG_FEATURE_MSC_INFO { //! \} +#ifdef __cplusplus + +//! \brief Contains the state of an individual system handle at the time the +//! snapshot was taken. This structure is Windows-specific. +//! +//! \sa MINIDUMP_HANDLE_DESCRIPTOR +struct __attribute__((packed, aligned(4))) MINIDUMP_HANDLE_DESCRIPTOR_2 + : public MINIDUMP_HANDLE_DESCRIPTOR { + //! \brief An RVA to a MINIDUMP_HANDLE_OBJECT_INFORMATION structure that + //! specifies object-specific information. This member can be zero if + //! there is no extra information. + RVA ObjectInfoRva; + + //! \brief Must be zero. + uint32_t Reserved0; +}; + //! \brief Information about the process that the minidump file contains a //! snapshot of, as well as the system that hosted that process. //! @@ -208,7 +210,7 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_4 //! //! On Windows 8.1 (NT 6.3), this is “6.3.9600.17031 //! (winblue_gdr.140221-1952)”. - base::char16 BuildString[260]; + wchar_t BuildString[260]; //! \brief The minidump producer’s “build string”, a string identifying the //! module that produced a minidump file. @@ -217,7 +219,7 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_4 //! //! On Windows 8.1 (NT 6.3), this may be “dbghelp.i386,6.3.9600.16520” or //! “dbghelp.amd64,6.3.9600.16520” depending on CPU architecture. - base::char16 DbgBldStr[40]; + wchar_t DbgBldStr[40]; }; //! \brief Information about the process that the minidump file contains a @@ -246,4 +248,87 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_5 //! \brief The latest known version of the MINIDUMP_MISC_INFO structure. typedef MINIDUMP_MISC_INFO_5 MINIDUMP_MISC_INFO_N; +#else + +struct MINIDUMP_HANDLE_DESCRIPTOR_2 { + ULONG64 Handle; + RVA TypeNameRva; + RVA ObjectNameRva; + ULONG32 Attributes; + ULONG32 GrantedAccess; + ULONG32 HandleCount; + ULONG32 PointerCount; + RVA ObjectInfoRva; + uint32_t Reserved0; +}; + +struct MINIDUMP_MISC_INFO_3 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; + uint32_t ProcessIntegrityLevel; + uint32_t ProcessExecuteFlags; + uint32_t ProtectedProcess; + uint32_t TimeZoneId; + TIME_ZONE_INFORMATION TimeZone; +}; + +struct MINIDUMP_MISC_INFO_4 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; + uint32_t ProcessIntegrityLevel; + uint32_t ProcessExecuteFlags; + uint32_t ProtectedProcess; + uint32_t TimeZoneId; + TIME_ZONE_INFORMATION TimeZone; + wchar_t BuildString[260]; + wchar_t DbgBldStr[40]; +}; + +struct MINIDUMP_MISC_INFO_5 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; + uint32_t ProcessIntegrityLevel; + uint32_t ProcessExecuteFlags; + uint32_t ProtectedProcess; + uint32_t TimeZoneId; + TIME_ZONE_INFORMATION TimeZone; + wchar_t BuildString[260]; + wchar_t DbgBldStr[40]; + struct XSTATE_CONFIG_FEATURE_MSC_INFO XStateData; + uint32_t ProcessCookie; +}; + +typedef struct MINIDUMP_MISC_INFO_5 MINIDUMP_MISC_INFO_N; + +#endif + +#pragma clang diagnostic pop + #endif // CRASHPAD_COMPAT_MINGW_DBGHELP_H_ From 66c69eece9b43c78fe3d0957f708f2f2a461b1f3 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 14 Apr 2020 10:49:05 +0200 Subject: [PATCH 020/478] build: bump submodules to versions specified in DEPS --- third_party/lss/lss | 2 +- third_party/mini_chromium/mini_chromium | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/lss/lss b/third_party/lss/lss index fd00dbbd0c..7bde79cc27 160000 --- a/third_party/lss/lss +++ b/third_party/lss/lss @@ -1 +1 @@ -Subproject commit fd00dbbd0c06a309c657d89e9430143b179ff6db +Subproject commit 7bde79cc274d06451bf65ae82c012a5d3e476b5a diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index f8f1182adb..bbf1307928 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit f8f1182adb804675b2aa4fb3ce03f6f884fae474 +Subproject commit bbf1307928bb7a9d1eda6be576283c8093b2775b From 1d9a0b7dd3eeaefb927fd3c827ca9b060f4018f0 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 14 Apr 2020 11:17:53 +0200 Subject: [PATCH 021/478] build: sync sources --- README.getsentry.md | 2 +- third_party/mini_chromium/CMakeLists.txt | 3 ++- util/CMakeLists.txt | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/README.getsentry.md b/README.getsentry.md index 693e96f03b..0c35f9f987 100644 --- a/README.getsentry.md +++ b/README.getsentry.md @@ -41,7 +41,7 @@ included files): - `./snapshot/CMakeLists.txt` - `./third_party/getopt/CMakeLists.txt` - `./third_party/mini_chromium/CMakeLists.txt` -- `./third_party/lib/CMakeLists.txt` +- `./third_party/zlib/CMakeLists.txt` - `./tools/CMakeLists.txt` - `./util/CMakeLists.txt` diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 8cdff52175..3774a62c0a 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -44,7 +44,7 @@ mc_append_sources( process/process_metrics.h rand_util.cc rand_util.h - scoped_clear_errno.h + scoped_clear_last_error.h scoped_generic.h stl_util.h strings/string16.cc @@ -106,6 +106,7 @@ endif() if(WIN32) mc_append_sources( process/process_metrics_win.cc + scoped_clear_last_error_win.cc strings/string_util_win.cc strings/string_util_win.h synchronization/lock_impl_win.cc diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 523bfe792d..93b0052c90 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -11,6 +11,8 @@ add_library(crashpad_util STATIC file/file_writer.cc file/file_writer.h file/filesystem.h + file/output_stream_file_writer.cc + file/output_stream_file_writer.h file/scoped_remove_file.cc file/scoped_remove_file.h file/string_file.cc @@ -86,6 +88,14 @@ add_library(crashpad_util STATIC stdlib/strnlen.cc stdlib/strnlen.h stdlib/thread_safe_vector.h + stream/base94_output_stream.cc + stream/base94_output_stream.h + stream/file_encoder.cc + stream/file_encoder.h + stream/file_output_stream.cc + stream/file_output_stream.h + stream/log_output_stream.cc + stream/log_output_stream.h stream/output_stream_interface.h stream/zlib_output_stream.cc stream/zlib_output_stream.h @@ -182,6 +192,13 @@ if(APPLE) ) endif() +if(ANDROID) + target_sources(crashpad_util PRIVATE + linux/initial_signal_dispositions.cc + linux/initial_signal_dispositions.h + ) +endif() + if(LINUX OR ANDROID) target_sources(crashpad_util PRIVATE net/http_transport_socket.cc @@ -260,6 +277,8 @@ if(WIN32) win/handle.h win/initial_client_data.cc win/initial_client_data.h + win/loader_lock.cc + win/loader_lock.h win/module_version.cc win/module_version.h win/nt_internals.cc From 4f3e36260fb7c97b717ad1fdc34ec0771328cc24 Mon Sep 17 00:00:00 2001 From: Amphaal Date: Sat, 18 Apr 2020 10:02:00 +0200 Subject: [PATCH 022/478] build(MinGW) Work around missing include (#13) --- util/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 93b0052c90..121dac9874 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -383,6 +383,13 @@ if(WIN32) "__STDC_VERSION__=199901L" $<$:__MINGW32__> ) + #exception_handler_server.cc missing header ? + set_source_files_properties( + win/exception_handler_server.cc + PROPERTIES + COMPILE_FLAGS + "-include memory" + ) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_util PRIVATE From 55b7a3cc58e16e3bdd036060b266ace1edeef89a Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Wed, 17 Jun 2020 13:21:51 -0700 Subject: [PATCH 023/478] cmake: Expose crashpad_handler static library (#14) --- handler/CMakeLists.txt | 51 +++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index f9d23b6949..6f14b6cd05 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -1,5 +1,4 @@ -add_executable(crashpad_handler WIN32 - main.cc +add_library(crashpad_handler_lib STATIC crash_report_upload_thread.cc crash_report_upload_thread.h handler_main.cc @@ -13,7 +12,7 @@ add_executable(crashpad_handler WIN32 ) if(APPLE) - target_sources(crashpad_handler PRIVATE + target_sources(crashpad_handler_lib PRIVATE mac/crash_report_exception_handler.cc mac/crash_report_exception_handler.h mac/exception_handler_server.cc @@ -24,7 +23,7 @@ if(APPLE) endif() if(LINUX OR ANDROID) - target_sources(crashpad_handler PRIVATE + target_sources(crashpad_handler_lib PRIVATE linux/capture_snapshot.cc linux/capture_snapshot.h linux/crash_report_exception_handler.cc @@ -35,25 +34,57 @@ if(LINUX OR ANDROID) endif() if(LINUX) - target_sources(crashpad_handler PRIVATE + target_sources(crashpad_handler_lib PRIVATE linux/cros_crash_report_exception_handler.cc linux/cros_crash_report_exception_handler.h ) endif() if(WIN32) - target_sources(crashpad_handler PRIVATE + target_sources(crashpad_handler_lib PRIVATE win/crash_report_exception_handler.cc win/crash_report_exception_handler.h ) endif() +target_link_libraries(crashpad_handler_lib + PRIVATE + $ + PUBLIC + crashpad_compat + crashpad_minidump + crashpad_snapshot + crashpad_util + mini_chromium +) + +if(WIN32) + if(MSVC) + target_compile_options(crashpad_handler_lib PRIVATE "/wd4201") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_handler_lib PRIVATE + "-Wno-multichar" + ) + endif() +endif() + +set_property(TARGET crashpad_handler_lib PROPERTY EXPORT_NAME handler) +add_library(crashpad::handler_lib ALIAS crashpad_handler_lib) + +crashpad_install_target(crashpad_handler_lib) + +add_executable(crashpad_handler WIN32 + main.cc +) + target_link_libraries(crashpad_handler PRIVATE $ PUBLIC crashpad_client crashpad_getopt + crashpad_handler_lib crashpad_minidump crashpad_snapshot crashpad_tools @@ -61,16 +92,10 @@ target_link_libraries(crashpad_handler mini_chromium ) -if(WIN32) +if(WIN32) if(MSVC) - target_compile_options(crashpad_handler PRIVATE "/wd4201") target_link_options(crashpad_handler PRIVATE "/SUBSYSTEM:WINDOWS") endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_handler PRIVATE - "-Wno-multichar" - ) - endif() endif() set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME handler) From 49efa56e5ed5ff37d551893358d75885c6ef9aab Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Thu, 18 Jun 2020 00:46:46 -0700 Subject: [PATCH 024/478] fix: Make linux build work (#15) --- CMakeLists.txt | 2 +- compat/CMakeLists.txt | 8 ++++++-- third_party/mini_chromium/CMakeLists.txt | 5 +++++ util/CMakeLists.txt | 5 +++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfe31311a0..8b9ca022c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) project(crashpad LANGUAGES C CXX) set(CRASHPAD_MAIN_PROJECT OFF) diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index 860a6e0731..ca660ed2db 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -93,6 +93,10 @@ else() ) endif() +if(LINUX) + target_link_libraries(crashpad_compat PRIVATE dl) +endif() + if(MSVC) target_include_directories(crashpad_compat ${TI_TYPE} "$") elseif(MINGW) @@ -108,11 +112,11 @@ else() endif() if(LINUX OR ANDROID) - target_include_directories(crashpad_compat ${TI_YPE} "$") + target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() if(ANDROID) - target_include_directories(crashpad_compat ${TI_YPE} "$") + target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() set_property(TARGET crashpad_compat PROPERTY EXPORT_NAME compat) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 3774a62c0a..6e1c126564 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -135,6 +135,11 @@ if(APPLE) "-framework Security" ) endif() + +if(LINUX) + target_link_libraries(mini_chromium PRIVATE pthread) +endif() + target_include_directories(mini_chromium PUBLIC "$" $ diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 121dac9874..48234c2a1b 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -239,6 +239,7 @@ if(LINUX OR ANDROID) linux/traits.h misc/capture_context_linux.S misc/paths_linux.cc + misc/time_linux.cc posix/process_info_linux.cc process/process_memory_linux.cc process/process_memory_linux.h @@ -371,6 +372,10 @@ if(APPLE) ) endif() +if(LINUX) + target_link_libraries(crashpad_util PRIVATE pthread) +endif() + if(WIN32) target_link_libraries(crashpad_util PRIVATE user32 version winhttp) if(MSVC) From 1ca6debce9b972f9dc7f8a4c54458e6d1956ab5f Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 26 Jun 2020 12:42:56 +0200 Subject: [PATCH 025/478] build: Update CMake files and submodules --- README.getsentry.md | 11 +++- client/CMakeLists.txt | 17 +++++- compat/CMakeLists.txt | 17 ++++++ handler/CMakeLists.txt | 52 ++++++++-------- snapshot/CMakeLists.txt | 21 ++++++- third_party/mini_chromium/CMakeLists.txt | 31 +++++++++- third_party/mini_chromium/mini_chromium | 2 +- util/CMakeLists.txt | 78 ++++++++++++++++-------- 8 files changed, 171 insertions(+), 58 deletions(-) diff --git a/README.getsentry.md b/README.getsentry.md index 0c35f9f987..c7824e1ce9 100644 --- a/README.getsentry.md +++ b/README.getsentry.md @@ -4,7 +4,7 @@ https://github.com/Youw/crashpad/, distributed with Apache 2.0 License. - Add `throws` declaration to `memfd_create` for compatibility with different libc versions. -- Build System Changes Listed Below +- Build System Changes Listed Below. - MinGW build support. # Build System Changes @@ -55,6 +55,15 @@ MinGW support adds the following files which need to be kept in sync. - `compat/mingw/` - `third_party/mini_chromium/utf_string_conversion_utils.mingw.cc` +## Building for iOS + +Build support for iOS, or Xcode in general is still a work in progress. +Once complete, creating a iOS compatible Xcode project should be as easy as: + + cmake -B cmakebuild -GXcode -DCMAKE_SYSTEM_NAME=iOS + +See the [upstream CMake Docs on iOS](https://cmake.org/cmake/help/v3.17/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-or-watchos) for further info. + # How To Update - Bump the submodules to the commit hashes specified in `./DEPS` diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 57d10a9eb8..b1a77c1944 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(crashpad_client STATIC simulate_crash.h ) -if(APPLE) +if(APPLE AND NOT IOS) target_sources(crashpad_client PRIVATE crash_report_database_mac.mm crashpad_client_mac.cc @@ -26,6 +26,13 @@ if(APPLE) ) endif() +if(IOS) + target_sources(crashpad_client PRIVATE + crash_report_database_mac.mm + crashpad_client_ios.cc + ) +endif() + if(LINUX OR ANDROID) target_sources(crashpad_client PRIVATE crashpad_client_linux.cc @@ -84,6 +91,14 @@ if(WIN32) endif() endif() +if(IOS) + target_link_libraries(crashpad_client + PUBLIC + crashpad_minidump + crashpad_snapshot + ) +endif() + crashpad_install_target(crashpad_client) crashpad_install_dev(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/client" diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index ca660ed2db..33870a5319 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -5,6 +5,7 @@ if(APPLE) mac/AvailabilityMacros.h mac/kern/exc_resource.h mac/mach-o/loader.h + mac/mach/i386/thread_state.h mac/mach/mach.h mac/sys/resource.h ) @@ -17,6 +18,16 @@ else() ) endif() +if(IOS) + list(APPEND COMPAT_SOURCES + ios/mach/exc.defs + ios/mach/mach_exc.defs + ios/mach/mach_types.defs + ios/mach/machine/machine_types.defs + ios/mach/std_types.defs + ) +endif() + if(LINUX OR ANDROID) list(APPEND COMPAT_SOURCES linux/signal.h @@ -111,8 +122,14 @@ else() target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() +if(IOS) + target_include_directories(crashpad_compat ${TI_TYPE} "$") +endif() + if(LINUX OR ANDROID) target_include_directories(crashpad_compat ${TI_TYPE} "$") +else() + target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() if(ANDROID) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 6f14b6cd05..a0b5d2deeb 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -74,33 +74,35 @@ add_library(crashpad::handler_lib ALIAS crashpad_handler_lib) crashpad_install_target(crashpad_handler_lib) -add_executable(crashpad_handler WIN32 - main.cc -) +if(NOT IOS) + add_executable(crashpad_handler WIN32 + main.cc + ) -target_link_libraries(crashpad_handler - PRIVATE - $ - PUBLIC - crashpad_client - crashpad_getopt - crashpad_handler_lib - crashpad_minidump - crashpad_snapshot - crashpad_tools - crashpad_util - mini_chromium -) + target_link_libraries(crashpad_handler + PRIVATE + $ + PUBLIC + crashpad_client + crashpad_getopt + crashpad_handler_lib + crashpad_minidump + crashpad_snapshot + crashpad_tools + crashpad_util + mini_chromium + ) -if(WIN32) - if(MSVC) - target_link_options(crashpad_handler PRIVATE "/SUBSYSTEM:WINDOWS") + if(WIN32) + if(MSVC) + target_link_options(crashpad_handler PRIVATE "/SUBSYSTEM:WINDOWS") + endif() endif() -endif() -set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME handler) -add_executable(crashpad::handler ALIAS crashpad_handler) + set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME handler) + add_executable(crashpad::handler ALIAS crashpad_handler) -install(TARGETS crashpad_handler EXPORT crashpad_export - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" -) + install(TARGETS crashpad_handler EXPORT crashpad_export + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) +endif() \ No newline at end of file diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 4bbd757676..bc8ec7cf2c 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -47,7 +47,7 @@ add_library(crashpad_snapshot STATIC ) -if(APPLE) +if(APPLE AND NOT IOS) target_sources(crashpad_snapshot PRIVATE posix/timezone.cc posix/timezone.h @@ -80,6 +80,25 @@ if(APPLE) mac/thread_snapshot_mac.cc mac/thread_snapshot_mac.h ) +elseif(IOS) + target_sources(crashpad_snapshot PRIVATE + posix/timezone.cc + posix/timezone.h + ios/exception_snapshot_ios.cc + ios/exception_snapshot_ios.h + ios/memory_snapshot_ios.cc + ios/memory_snapshot_ios.h + ios/module_snapshot_ios.cc + ios/module_snapshot_ios.h + ios/process_snapshot_ios.cc + ios/process_snapshot_ios.h + ios/system_snapshot_ios.cc + ios/system_snapshot_ios.h + ios/thread_snapshot_ios.cc + ios/thread_snapshot_ios.h + mac/cpu_context_mac.cc + mac/cpu_context_mac.h + ) else() target_sources(crashpad_snapshot PRIVATE crashpad_types/crashpad_info_reader.cc diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 6e1c126564..320f9aae89 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -11,6 +11,8 @@ mc_append_sources( atomicops_internals_portable.h auto_reset.h bit_cast.h + check.h + check_op.h compiler_specific.h debug/alias.cc debug/alias.h @@ -81,7 +83,7 @@ else() ) endif() -if(APPLE) +if(APPLE AND NOT IOS) mc_append_sources( mac/close_nocancel.cc mac/foundation_util.h @@ -101,6 +103,23 @@ if(APPLE) mac/scoped_typeref.h strings/sys_string_conversions_mac.mm ) +elseif(IOS) + mc_append_sources( + mac/foundation_util.h + mac/foundation_util.mm + mac/mach_logging.cc + mac/mach_logging.h + mac/scoped_cftyperef.h + mac/scoped_mach_port.cc + mac/scoped_mach_port.h + mac/scoped_mach_vm.cc + mac/scoped_mach_vm.h + mac/scoped_nsautorelease_pool.h + mac/scoped_nsautorelease_pool.mm + mac/scoped_nsobject.h + mac/scoped_typeref.h + strings/sys_string_conversions_mac.mm + ) endif() if(WIN32) @@ -126,7 +145,7 @@ else() ) endif() -if(APPLE) +if(APPLE AND NOT IOS) target_link_libraries(mini_chromium PUBLIC "-framework ApplicationServices" "-framework CoreFoundation" @@ -134,6 +153,14 @@ if(APPLE) "-framework IOKit" "-framework Security" ) +elseif(IOS) + target_link_libraries(mini_chromium PUBLIC + "-framework CoreFoundation" + "-framework CoreGraphics" + "-framework CoreText" + "-framework Foundation" + "-framework Security" + ) endif() if(LINUX) diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index bbf1307928..ae14a14ab4 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit bbf1307928bb7a9d1eda6be576283c8093b2775b +Subproject commit ae14a14ab4cea36db9c446741581d427a7fc7f89 diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 48234c2a1b..14f3903131 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -2,6 +2,8 @@ add_library(crashpad_util STATIC file/delimited_file_reader.cc file/delimited_file_reader.h file/directory_reader.h + file/file_helper.cc + file/file_helper.h file/file_io.cc file/file_io.h file/file_reader.cc @@ -141,20 +143,8 @@ endif() if(APPLE) target_sources(crashpad_util PRIVATE - mac/checked_mach_address_range.h - mac/launchd.h - mac/launchd.mm - mac/mac_util.cc - mac/mac_util.h - mac/service_management.cc - mac/service_management.h mac/xattr.cc mac/xattr.h - mach/child_port_handshake.cc - mach/child_port_handshake.h - mach/child_port_server.cc - mach/child_port_server.h - mach/child_port_types.h mach/composite_mach_message_server.cc mach/composite_mach_message_server.h mach/exc_client_variants.cc @@ -165,31 +155,56 @@ if(APPLE) mach/exception_behaviors.h mach/exception_ports.cc mach/exception_ports.h - mach/exception_types.cc - mach/exception_types.h mach/mach_extensions.cc mach/mach_extensions.h mach/mach_message.cc mach/mach_message.h mach/mach_message_server.cc mach/mach_message_server.h - mach/notify_server.cc - mach/notify_server.h - mach/scoped_task_suspend.cc - mach/scoped_task_suspend.h mach/symbolic_constants_mach.cc mach/symbolic_constants_mach.h - mach/task_for_pid.cc - mach/task_for_pid.h misc/capture_context_mac.S misc/clock_mac.cc misc/paths_mac.cc - net/http_transport_mac.mm - posix/process_info_mac.cc - process/process_memory_mac.cc - process/process_memory_mac.h synchronization/semaphore_mac.cc ) + if(NOT IOS) + target_sources(crashpad_util PRIVATE + mac/checked_mach_address_range.h + mac/launchd.h + mac/launchd.mm + mac/mac_util.cc + mac/mac_util.h + mac/service_management.cc + mac/service_management.h + mach/bootstrap.cc + mach/bootstrap.h + mach/child_port_handshake.cc + mach/child_port_handshake.h + mach/child_port_server.cc + mach/child_port_server.h + mach/child_port_types.h + mach/exception_types.cc + mach/exception_types.h + mach/notify_server.cc + mach/notify_server.h + mach/scoped_task_suspend.cc + mach/scoped_task_suspend.h + mach/task_for_pid.cc + mach/task_for_pid.h + net/http_transport_mac.mm + posix/process_info_mac.cc + process/process_memory_mac.cc + process/process_memory_mac.h + ) + elseif() + target_sources(crashpad_util PRIVATE + ios/exception_processor.h + ios/exception_processor.mm + ios/ios_system_data_collector.h + ios/ios_system_data_collector.mm + ) + endif() endif() if(ANDROID) @@ -298,11 +313,13 @@ if(WIN32) win/scoped_local_alloc.h win/scoped_process_suspend.cc win/scoped_process_suspend.h + win/scoped_registry_key.h win/scoped_set_event.cc win/scoped_set_event.h win/session_end_watcher.cc win/session_end_watcher.h win/termination_codes.h + win/traits.h win/xp_compat.h misc/capture_context_win.asm win/safe_terminate_process.asm @@ -311,8 +328,16 @@ endif() # Copied from: https://github.com/qedsoftware/crashpad/blob/3583c50a6575857abcf140f6ea3b8d11390205b3/util/CMakeLists.txt#L196-L233 if(APPLE) - set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") - set(input_files "") + if(NOT IOS) + set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") + set(input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") + elseif() + set(def_relative_files "") + set(input_files + "${CMAKE_CURRENT_LIST_DIR}/../third_party/xnu/osfmk/mach/exc.defs" + "${CMAKE_CURRENT_LIST_DIR}/../third_party/xnu/osfmk/mach/mach_exc.defs" + ) + endif() foreach(x ${def_relative_files}) # CMAKE_OSX_SYSROOT may be empty (e.g. for Makefile generators), # in this case files will be taken from root. @@ -322,7 +347,6 @@ if(APPLE) endif() list(APPEND input_files "${full_path}") endforeach() - list(APPEND input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") find_package(PythonInterp 2.7 REQUIRED) From 24a338862007de81a003e7187b1f2c44378140a0 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 26 Jun 2020 16:04:12 +0200 Subject: [PATCH 026/478] feat: Rework attachment support patch --- client/crash_report_database.cc | 10 +-- client/crash_report_database.h | 4 +- client/crash_report_database_generic.cc | 8 ++ client/crash_report_database_mac.mm | 8 ++ client/crash_report_database_test.cc | 29 +++---- client/crash_report_database_win.cc | 75 ----------------- client/crashpad_client.h | 13 --- client/crashpad_client_linux.cc | 25 ------ client/crashpad_client_mac.cc | 47 ++++------- client/crashpad_client_win.cc | 27 ------- handler/handler_main.cc | 81 +++++-------------- .../linux/crash_report_exception_handler.cc | 17 ---- .../linux/crash_report_exception_handler.h | 1 - handler/mac/crash_report_exception_handler.cc | 36 +++++---- handler/mac/crash_report_exception_handler.h | 10 +-- handler/win/crash_report_exception_handler.h | 1 - 16 files changed, 90 insertions(+), 302 deletions(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index 65b0c31d61..e1559ca738 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -18,14 +18,6 @@ namespace crashpad { -bool CrashReportDatabase::AttachmentNameIsOK(const std::string& name) { - for (const char c : name) { - if (c != '_' && c != '-' && c != '.' && !isalnum(c)) - return false; - } - return true; -} - CrashReportDatabase::Report::Report() : uuid(), file_path(), @@ -95,7 +87,7 @@ CrashReportDatabase::UploadReport::~UploadReport() { } } -bool CrashReportDatabase::UploadReport::Initialize(const base::FilePath& path, +bool CrashReportDatabase::UploadReport::Initialize(const base::FilePath path, CrashReportDatabase* db) { database_ = db; InitializeAttachments(); diff --git a/client/crash_report_database.h b/client/crash_report_database.h index 8fb294b519..ce317f7972 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -181,7 +181,7 @@ class CrashReportDatabase { friend class CrashReportDatabaseMac; friend class CrashReportDatabaseWin; - bool Initialize(const base::FilePath& path, CrashReportDatabase* database); + bool Initialize(const base::FilePath path, CrashReportDatabase* database); void InitializeAttachments(); std::unique_ptr reader_; @@ -406,8 +406,6 @@ class CrashReportDatabase { protected: CrashReportDatabase() {} - static bool AttachmentNameIsOK(const std::string& name); - private: //! \brief Adjusts a crash report record’s metadata to account for an upload //! attempt, and updates the last upload attempt time as returned by diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index 376c4d1a6a..aeaf2af43f 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -44,6 +44,14 @@ UUID UUIDFromReportPath(const base::FilePath& path) { return uuid; } +bool AttachmentNameIsOK(const std::string& name) { + for (const char c : name) { + if (c != '_' && c != '-' && c != '.' && !isalnum(c)) + return false; + } + return true; +} + using OperationStatus = CrashReportDatabase::OperationStatus; constexpr base::FilePath::CharType kSettings[] = diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 57891d4bb6..d3a366bde8 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -71,6 +71,14 @@ constexpr char kXattrDatabaseInitialized[] = "initialized"; +bool AttachmentNameIsOK(const std::string& name) { + for (const char c : name) { + if (c != '_' && c != '-' && c != '.' && !isalnum(c)) + return false; + } + return true; +} + // Ensures that the node at |path| is a directory. If the |path| refers to a // file, rather than a directory, returns false. Otherwise, returns true, // indicating that |path| already was a directory. diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index a4541512e7..20512a4509 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -674,6 +674,10 @@ TEST_F(CrashReportDatabaseTest, RequestUpload) { } TEST_F(CrashReportDatabaseTest, Attachments) { +#if defined(OS_MACOSX) || defined(OS_WIN) + // Attachments aren't supported on Mac and Windows yet. + GTEST_SKIP(); +#else std::unique_ptr new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), CrashReportDatabase::kNoError); @@ -712,9 +716,16 @@ TEST_F(CrashReportDatabaseTest, Attachments) { char result_buffer[sizeof(test_data)]; result_attachments["some_file"]->Read(result_buffer, sizeof(result_buffer)); EXPECT_EQ(memcmp(test_data, result_buffer, sizeof(test_data)), 0); +#endif } TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { +#if defined(OS_MACOSX) || defined(OS_WIN) + // Attachments aren't supported on Mac and Windows yet. + GTEST_SKIP(); +#else + // TODO: This is using paths that are specific to the generic implementation + // and will need to be generalized for Mac and Windows. std::unique_ptr new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), CrashReportDatabase::kNoError); @@ -736,27 +747,16 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { ASSERT_TRUE(LoggingRemoveFile(report.file_path)); -// Additional check for Generic database -#if !defined(OS_MACOSX) && !defined(OS_WIN) ASSERT_TRUE(LoggingRemoveFile(base::FilePath( report.file_path.RemoveFinalExtension().value() + ".meta"))); -#endif ASSERT_EQ(db()->LookUpCrashReport(uuid, &report), CrashReportDatabase::kReportNotFound); -#ifdef OS_WIN - auto uuid_str = uuid.ToString16(); -#else - auto uuid_str = uuid.ToString(); -#endif - base::FilePath report_attachments_dir( - path().Append(FILE_PATH_LITERAL("attachments")).Append(uuid_str)); - base::FilePath file_path1( - report_attachments_dir.Append(FILE_PATH_LITERAL("file1"))); - base::FilePath file_path2( - report_attachments_dir.Append(FILE_PATH_LITERAL("file2"))); + path().Append("attachments").Append(uuid.ToString())); + base::FilePath file_path1(report_attachments_dir.Append("file1")); + base::FilePath file_path2(report_attachments_dir.Append("file2")); EXPECT_TRUE(FileExists(file_path1)); EXPECT_TRUE(FileExists(file_path1)); @@ -765,6 +765,7 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { EXPECT_FALSE(FileExists(file_path1)); EXPECT_FALSE(FileExists(file_path2)); EXPECT_FALSE(FileExists(report_attachments_dir)); +#endif } // This test uses knowledge of the database format to break it, so it only diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 51a8472848..f1a4960851 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -41,7 +41,6 @@ namespace { constexpr wchar_t kReportsDirectory[] = L"reports"; constexpr wchar_t kMetadataFileName[] = L"metadata"; -constexpr wchar_t kAttachmentsDirectory[] = L"attachments"; constexpr wchar_t kSettings[] = L"settings.dat"; @@ -664,16 +663,6 @@ class CrashReportDatabaseWin : public CrashReportDatabase { std::unique_ptr AcquireMetadata(); - //! \brief Cleans any attachments that have no associated report. - void CleanOrphanedAttachments(); - - //! \brief Attempt to remove any attachments associated with the given - //! report UUID. - //! There may not be any, so failing is not an error. - //! - //! \param[in] uuid The report identifier which attachments to remove. - void RemoveAttachmentsByUUID(const UUID& uuid); - base::FilePath base_dir_; Settings settings_; InitializationStateDcheck initialized_; @@ -692,11 +681,6 @@ base::FilePath CrashReportDatabaseWin::AttachmentsPath(const UUID& uuid) { FileWriter* CrashReportDatabase::NewReport::AddAttachment( const std::string& name) { - if (!AttachmentNameIsOK(name)) { - LOG(ERROR) << "invalid name for attachment " << name; - return nullptr; - } - auto database_win = static_cast(database_); base::FilePath attachments_root_dir = database_win->AttachmentsRootPath(); base::FilePath attachments_dir = database_win->AttachmentsPath(uuid_); @@ -769,9 +753,6 @@ bool CrashReportDatabaseWin::Initialize(bool may_create) { if (!CreateDirectoryIfNecessary(base_dir_.Append(kReportsDirectory))) return false; - if (!CreateDirectoryIfNecessary(base_dir_.Append(kAttachmentsDirectory))) - return false; - if (!settings_.Initialize(base_dir_.Append(kSettings))) return false; @@ -1000,62 +981,6 @@ std::unique_ptr CrashReportDatabaseWin::AcquireMetadata() { return Metadata::Create(metadata_file, base_dir_.Append(kReportsDirectory)); } -void CrashReportDatabaseWin::CleanOrphanedAttachments() { - base::FilePath root_attachments_dir(base_dir_.Append(kAttachmentsDirectory)); - DirectoryReader reader; - if (!reader.Open(root_attachments_dir)) { - LOG(ERROR) << "no attachments dir"; - return; - } - - std::unique_ptr metadata(AcquireMetadata()); - if (!metadata) - return; - - base::FilePath filename; - DirectoryReader::Result result; - while ((result = reader.NextFile(&filename)) == - DirectoryReader::Result::kSuccess) { - const base::FilePath path(root_attachments_dir.Append(filename)); - if (IsDirectory(path, false)) { - UUID uuid; - if (!uuid.InitializeFromString(filename.value())) { - LOG(ERROR) << "unexpected attachment dir name " - << base::UTF16ToUTF8(filename.value()); - continue; - } - - // Check to see if the report exist. - const ReportDisk* report_disk; - const OperationStatus os = metadata->FindSingleReport(uuid, &report_disk); - if (os != OperationStatus::kReportNotFound) { - continue; - } - - // Couldn't find a report, assume these attachments are orphaned. - RemoveAttachmentsByUUID(uuid); - } - } -} - -void CrashReportDatabaseWin::RemoveAttachmentsByUUID(const UUID &uuid) { - base::FilePath attachments_dir = AttachmentsPath(uuid); - DirectoryReader reader; - if (!reader.Open(attachments_dir)) { - return; - } - - base::FilePath filename; - DirectoryReader::Result result; - while ((result = reader.NextFile(&filename)) == - DirectoryReader::Result::kSuccess) { - const base::FilePath filepath(attachments_dir.Append(filename)); - LoggingRemoveFile(filepath); - } - - LoggingRemoveDirectory(attachments_dir); -} - std::unique_ptr InitializeInternal( const base::FilePath& path, bool may_create) { diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 256d7f0b70..6f8c2fe018 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -121,19 +121,6 @@ class CrashpadClient { bool asynchronous_start, const std::vector& attachments = {}); -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) - bool StartHandlerWithAttachments( - const base::FilePath& handler, - const base::FilePath& database, - const base::FilePath& metrics_dir, - const std::string& url, - const std::map& annotations, - const std::map& fileAttachments, - const std::vector& arguments, - bool restartable, - bool asynchronous_start); -#endif // OS_WIN || OS_MACOSX || OS_LINUX - #if defined(OS_ANDROID) || defined(OS_LINUX) || DOXYGEN //! \brief Retrieve the socket and process ID for the handler. //! diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 819db97e9b..4fb99d846f 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -402,31 +402,6 @@ bool CrashpadClient::StartHandler( std::move(client_sock), handler_pid, &unhandled_signals_); } -bool CrashpadClient::StartHandlerWithAttachments( - const base::FilePath& handler, - const base::FilePath& database, - const base::FilePath& metrics_dir, - const std::string& url, - const std::map& annotations, - const std::map& fileAttachments, - const std::vector& arguments, - bool restartable, - bool asynchronous_start) { - std::vector updated_arguments = arguments; - for (const auto& kv: fileAttachments) { - std::string attachmentArg = "--attachment=" + kv.first + "=" + kv.second.value(); - updated_arguments.push_back(attachmentArg); - } - - // FIXME this is not the same as calling StartHandler on e.g. Mac - return CrashpadClient::StartHandlerAtCrash(handler, - database, - metrics_dir, - url, - annotations, - updated_arguments); -} - #if defined(OS_ANDROID) || defined(OS_LINUX) // static bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) { diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 70c9469eef..13da5a46d4 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -123,6 +123,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { const std::string& url, const std::map& annotations, const std::vector& arguments, + const std::vector& attachments, bool restartable) { base::mac::ScopedMachReceiveRight receive_right( NewMachPort(MACH_PORT_RIGHT_RECEIVE)); @@ -162,6 +163,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { url, annotations, arguments, + attachments, std::move(receive_right), handler_restarter.get(), false)) { @@ -170,7 +172,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { if (handler_restarter && handler_restarter->StartRestartThread( - handler, database, metrics_dir, url, annotations, arguments)) { + handler, database, metrics_dir, url, annotations, arguments, attachments)) { // The thread owns the object now. ignore_result(handler_restarter.release()); } @@ -205,6 +207,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { url_, annotations_, arguments_, + attachments_, base::mac::ScopedMachReceiveRight(rights), this, true); @@ -221,6 +224,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { url_(), annotations_(), arguments_(), + attachments_(), notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)), last_start_time_(0) { } @@ -250,6 +254,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { const std::string& url, const std::map& annotations, const std::vector& arguments, + const std::vector& attachments, base::mac::ScopedMachReceiveRight receive_right, HandlerStarter* handler_restarter, bool restart) { @@ -330,6 +335,11 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { argv.push_back( FormatArgumentString("annotation", kv.first + '=' + kv.second)); } + + for (const auto& attachment : attachments) { + argv.push_back(FormatArgumentString("attachment", attachment.value())); + } + argv.push_back(FormatArgumentInt("handshake-fd", server_write_fd.get())); // When restarting, reset the system default crash handler first. Otherwise, @@ -365,13 +375,15 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { const base::FilePath& metrics_dir, const std::string& url, const std::map& annotations, - const std::vector& arguments) { + const std::vector& arguments, + const std::vector& attachments) { handler_ = handler; database_ = database; metrics_dir_ = metrics_dir; url_ = url; annotations_ = annotations; arguments_ = arguments; + attachments_ = attachments; pthread_attr_t pthread_attr; errno = pthread_attr_init(&pthread_attr); @@ -424,6 +436,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { std::string url_; std::map annotations_; std::vector arguments_; + std::vector attachments_; base::mac::ScopedMachReceiveRight notify_port_; uint64_t last_start_time_; @@ -448,9 +461,6 @@ bool CrashpadClient::StartHandler( bool restartable, bool asynchronous_start, const std::vector& attachments) { - // Attachments are not implemented on MacOS yet. - DCHECK(attachments.empty()); - // The “restartable” behavior can only be selected on OS X 10.10 and later. In // previous OS versions, if the initial client were to crash while attempting // to restart the handler, it would become an unkillable process. @@ -461,6 +471,7 @@ bool CrashpadClient::StartHandler( url, annotations, arguments, + attachments, restartable && MacOSXMinorVersion() >= 10)); if (!exception_port.is_valid()) { return false; @@ -470,32 +481,6 @@ bool CrashpadClient::StartHandler( return true; } -bool CrashpadClient::StartHandlerWithAttachments( - const base::FilePath& handler, - const base::FilePath& database, - const base::FilePath& metrics_dir, - const std::string& url, - const std::map& annotations, - const std::map& fileAttachments, - const std::vector& arguments, - bool restartable, - bool asynchronous_start) { - std::vector updated_arguments = arguments; - for (const auto& kv: fileAttachments) { - std::string attachmentArg = "--attachment=" + kv.first + "=" + kv.second.value(); - updated_arguments.push_back(attachmentArg); - } - - return StartHandler(handler, - database, - metrics_dir, - url, - annotations, - updated_arguments, - restartable, - asynchronous_start); -} - bool CrashpadClient::SetHandlerMachService(const std::string& service_name) { base::mac::ScopedMachSendRight exception_port(BootstrapLookUp(service_name)); if (!exception_port.is_valid()) { diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index a749c9ba5a..1f2fb819d0 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -669,33 +669,6 @@ bool CrashpadClient::StartHandler( } } -bool CrashpadClient::StartHandlerWithAttachments( - const base::FilePath& handler, - const base::FilePath& database, - const base::FilePath& metrics_dir, - const std::string& url, - const std::map& annotations, - const std::map& fileAttachments, - const std::vector& arguments, - bool restartable, - bool asynchronous_start) { - std::vector updated_arguments = arguments; - for (const auto& kv : fileAttachments) { - std::string attachmentArg = - "--attachment=" + kv.first + "=" + base::UTF16ToUTF8(kv.second.value()); - updated_arguments.push_back(attachmentArg); - } - - return StartHandler(handler, - database, - metrics_dir, - url, - annotations, - updated_arguments, - restartable, - asynchronous_start); -} - bool CrashpadClient::SetHandlerIPCPipe(const std::wstring& ipc_pipe) { DCHECK(ipc_pipe_.empty()); DCHECK(!ipc_pipe.empty()); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index b91f10d58d..83dbd75e86 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -101,7 +101,7 @@ void Usage(const base::FilePath& me) { "Crashpad's exception handler server.\n" "\n" " --annotation=KEY=VALUE set a process annotation in each crash report\n" -#if defined(OS_WIN) || defined(OS_LINUX) +#if !defined(OS_FUCHSIA) " --attachment=FILE_PATH attach specified file to each crash report\n" " at the time of the crash\n" #endif // OS_WIN || OS_LINUX @@ -160,9 +160,6 @@ void Usage(const base::FilePath& me) { #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" -#if !defined(OS_FUCHSIA) -" --attachment=NAME=PATH attach a copy of a file, along with a crash dump\n" -#endif #if defined(OS_CHROMEOS) " --use-cros-crash-reporter\n" " pass crash reports to /sbin/crash_reporter\n" @@ -187,7 +184,6 @@ void Usage(const base::FilePath& me) { struct Options { std::map annotations; std::map monitor_self_annotations; - std::map attachments; std::string url; base::FilePath database; base::FilePath metrics_dir; @@ -219,9 +215,9 @@ struct Options { base::FilePath minidump_dir_for_tests; bool always_allow_feedback = false; #endif // OS_CHROMEOS -#if defined(OS_WIN) || defined (OS_LINUX) +#if !defined(OS_FUCHSIA) std::vector attachments; -#endif // OS_WIN || OS_LINUX +#endif // !OS_FUCHSIA }; // Splits |key_value| on '=' and inserts the resulting key and value into |map|. @@ -246,30 +242,6 @@ bool AddKeyValueToMap(std::map* map, } return true; } -// Overloaded version, to accept base::FilePath as a VALUE. -bool AddKeyValueToMap(std::map* map, - const std::string& key_value, - const char* argument) { - std::string key; - std::string raw_value; - if (!SplitStringFirst(key_value, '=', &key, &raw_value)) { - LOG(ERROR) << argument << " requires NAME=PATH"; - return false; - } - -#ifdef OS_WIN - base::FilePath value(base::UTF8ToUTF16(raw_value)); -#else - base::FilePath value(raw_value); -#endif - - base::FilePath old_value; - if (!MapInsertOrReplace(map, key, value, &old_value)) { - LOG(WARNING) << argument << " has duplicate name " << key - << ", discarding value " << old_value.value().c_str(); - } - return true; -} // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is // to prevent multiple exit events from inadvertently being recorded, which @@ -551,9 +523,9 @@ int HandlerMain(int argc, // Long options without short equivalents. kOptionLastChar = 255, kOptionAnnotation, -#if defined(OS_WIN) || defined(OS_LINUX) +#if !defined(OS_FUCHSIA) kOptionAttachment, -#endif // OS_WIN || OS_LINUX +#endif // !OS_FUCHSIA kOptionDatabase, #if defined(OS_MACOSX) kOptionHandshakeFD, @@ -590,9 +562,6 @@ int HandlerMain(int argc, kOptionTraceParentWithException, #endif kOptionURL, -#if !defined(OS_FUCHSIA) - kOptionAttachment, -#endif #if defined(OS_CHROMEOS) kOptionUseCrosCrashReporter, kOptionMinidumpDirForTests, @@ -609,9 +578,9 @@ int HandlerMain(int argc, static constexpr option long_options[] = { {"annotation", required_argument, nullptr, kOptionAnnotation}, -#if defined(OS_WIN) || defined(OS_LINUX) +#if !defined(OS_FUCHSIA) {"attachment", required_argument, nullptr, kOptionAttachment}, -#endif // OS_WIN || OS_LINUX +#endif // !OS_FUCHSIA {"database", required_argument, nullptr, kOptionDatabase}, #if defined(OS_MACOSX) {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, @@ -675,22 +644,16 @@ int HandlerMain(int argc, kOptionTraceParentWithException}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, -#if !defined(OS_FUCHSIA) - {"attachment", required_argument, nullptr, kOptionAttachment}, -#endif #if defined(OS_CHROMEOS) {"use-cros-crash-reporter", - no_argument, - nullptr, - kOptionUseCrosCrashReporter}, + no_argument, + nullptr, + kOptionUseCrosCrashReporter}, {"minidump-dir-for-tests", - required_argument, - nullptr, - kOptionMinidumpDirForTests}, - {"always-allow-feedback", - no_argument, - nullptr, - kOptionAlwaysAllowFeedback}, + required_argument, + nullptr, + kOptionMinidumpDirForTests}, + {"always-allow-feedback", no_argument, nullptr, kOptionAlwaysAllowFeedback}, #endif // OS_CHROMEOS #if defined(OS_ANDROID) {"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog}, @@ -724,13 +687,13 @@ int HandlerMain(int argc, } break; } -#if defined(OS_WIN) || defined(OS_LINUX) +#if !defined(OS_FUCHSIA) case kOptionAttachment: { options.attachments.push_back(base::FilePath( ToolSupport::CommandLineArgumentToFilePathStringType(optarg))); break; } -#endif // OS_WIN || OS_LINUX +#endif // !OS_FUCHSIA case kOptionDatabase: { options.database = base::FilePath( ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); @@ -852,14 +815,6 @@ int HandlerMain(int argc, options.url = optarg; break; } -#if !defined(OS_FUCHSIA) - case kOptionAttachment: { - if (!AddKeyValueToMap(&options.attachments, optarg, "--attachment")) { - return ExitFailure(); - } - break; - } -#endif #if defined(OS_CHROMEOS) case kOptionUseCrosCrashReporter: { options.use_cros_crash_reporter = true; @@ -1050,9 +1005,9 @@ int HandlerMain(int argc, database.get(), static_cast(upload_thread.Get()), &options.annotations, -#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX) +#if !defined(OS_FUCHSIA) &options.attachments, -#endif // OS_WIN || OS_LINUX || OS_MACOSX +#endif // !OS_FUCHSIA #if defined(OS_ANDROID) options.write_minidump_to_database, options.write_minidump_to_log, diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index ac2a66d734..d6e54be7dd 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -193,23 +193,6 @@ bool CrashReportExceptionHandler::WriteMinidumpToDatabase( return false; } - if (process_attachments_) { - // Note that attachments are read at this point each time rather than once - // so that if the contents of the file has changed it will be re-read for - // each upload (e.g. in the case of a log file). - for (const auto& it : *process_attachments_) { - FileWriter* writer = new_report->AddAttachment(it.first); - if (writer) { - std::string contents; - if (!LoggingReadEntireFile(it.second, &contents)) { - // Not being able to read the file isn't considered fatal, and - // should not prevent the report from being processed. - continue; - } - writer->Write(contents.data(), contents.size()); - } - } - } bool write_minidump_to_log_succeed = false; if (write_minidump_to_log) { if (auto* file_reader = new_report->Reader()) { diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 69cf276b4e..ae28430171 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -18,7 +18,6 @@ #include #include -#include "base/files/file_path.h" #include "base/macros.h" #include "client/crash_report_database.h" #include "handler/crash_report_upload_thread.h" diff --git a/handler/mac/crash_report_exception_handler.cc b/handler/mac/crash_report_exception_handler.cc index fa620d741c..5113e1f4fb 100644 --- a/handler/mac/crash_report_exception_handler.cc +++ b/handler/mac/crash_report_exception_handler.cc @@ -27,6 +27,7 @@ #include "minidump/minidump_user_extension_stream_data_source.h" #include "snapshot/crashpad_info_client_options.h" #include "snapshot/mac/process_snapshot_mac.h" +#include "util/file/file_helper.h" #include "util/file/file_writer.h" #include "util/mach/bootstrap.h" #include "util/mach/exc_client_variants.h" @@ -46,12 +47,12 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, - const std::map* process_attachments, + const std::vector* attachments, const UserStreamDataSources* user_stream_data_sources) : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), - process_attachments_(process_attachments), + attachments_(attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() { @@ -181,22 +182,23 @@ kern_return_t CrashReportExceptionHandler::CatchMachException( return KERN_FAILURE; } - if (process_attachments_) { - // Note that attachments are read at this point each time rather than once - // so that if the contents of the file has changed it will be re-read for - // each upload (e.g. in the case of a log file). - for (const auto& it : *process_attachments_) { - FileWriter* writer = new_report->AddAttachment(it.first); - if (writer) { - std::string contents; - if (!LoggingReadEntireFile(it.second, &contents)) { - // Not being able to read the file isn't considered fatal, and - // should not prevent the report from being processed. - continue; - } - writer->Write(contents.data(), contents.size()); - } + for (const auto& attachment : (*attachments_)) { + FileReader file_reader; + if (!file_reader.Open(attachment)) { + LOG(ERROR) << "attachment " << attachment.value().c_str() + << " couldn't be opened, skipping"; + continue; } + + base::FilePath filename = attachment.BaseName(); + FileWriter* file_writer = new_report->AddAttachment(filename.value()); + if (file_writer == nullptr) { + LOG(ERROR) << "attachment " << filename.value().c_str() + << " couldn't be created, skipping"; + continue; + } + + CopyFileContent(&file_reader, file_writer); } UUID uuid; diff --git a/handler/mac/crash_report_exception_handler.h b/handler/mac/crash_report_exception_handler.h index a093603fe5..7df8e70091 100644 --- a/handler/mac/crash_report_exception_handler.h +++ b/handler/mac/crash_report_exception_handler.h @@ -50,10 +50,8 @@ class CrashReportExceptionHandler final //! To interoperate with Breakpad servers, the recommended practice is to //! specify values for the `"prod"` and `"ver"` keys as process //! annotations. - //! \param[in] process_attachments A map of file name keys to file paths to be - //! included in the report. Each time a report is written, the file paths - //! will be read in their entirety and included in the report using the - //! file name key as the name in the http upload. + //! \param[in] attachments A vector of file paths that should be captured with + //! each report at the time of the crash. //! \param[in] user_stream_data_sources Data sources to be used to extend //! crash reports. For each crash report that is written, the data sources //! are called in turn. These data sources may contribute additional @@ -62,7 +60,7 @@ class CrashReportExceptionHandler final CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map* process_annotations, - const std::map* process_attachments, + const std::vector* attachments, const UserStreamDataSources* user_stream_data_sources); ~CrashReportExceptionHandler(); @@ -91,7 +89,7 @@ class CrashReportExceptionHandler final CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map* process_annotations_; // weak - const std::map* process_attachments_; // weak + const std::vector* attachments_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); diff --git a/handler/win/crash_report_exception_handler.h b/handler/win/crash_report_exception_handler.h index 9fe61ec64a..cefb898194 100644 --- a/handler/win/crash_report_exception_handler.h +++ b/handler/win/crash_report_exception_handler.h @@ -20,7 +20,6 @@ #include #include -#include "base/files/file_path.h" #include "base/macros.h" #include "handler/user_stream_data_source.h" #include "util/win/exception_handler_server.h" From e778e67793ab5437ab1d09d7a35d25dffdb0f011 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 26 Jun 2020 16:57:30 +0200 Subject: [PATCH 027/478] fix: Fix broken ifdef upstream --- snapshot/crashpad_types/crashpad_info_reader.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/crashpad_types/crashpad_info_reader.cc b/snapshot/crashpad_types/crashpad_info_reader.cc index e4c8b93403..5f2f35601f 100644 --- a/snapshot/crashpad_types/crashpad_info_reader.cc +++ b/snapshot/crashpad_types/crashpad_info_reader.cc @@ -20,7 +20,7 @@ #include "client/crashpad_info.h" #include "util/misc/as_underlying_type.h" -#if defined(OS_WINDOWS) +#if defined(OS_WIN) #include "util/win/traits.h" #elif defined(OS_LINUX) || defined(OS_ANDROID) #include "util/linux/traits.h" From c4d5234f9024763094d7b978b246c2d4dbf54748 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 1 Jul 2020 12:04:44 +0200 Subject: [PATCH 028/478] build crashpad with openssl if possible --- CMakeLists.txt | 15 +++++++++++---- util/CMakeLists.txt | 21 ++++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b9ca022c7..abb06971a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 3.12) project(crashpad LANGUAGES C CXX) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(LINUX TRUE) +endif() + set(CRASHPAD_MAIN_PROJECT OFF) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(CRASHPAD_MAIN_PROJECT ON) @@ -20,6 +24,13 @@ if(CRASHPAD_ZLIB_SYSTEM) find_package(ZLIB REQUIRED) endif() +if(LINUX OR ANDROID) + find_package(OpenSSL) + if(OPENSSL_FOUND) + set(CRASHPAD_USE_BORINGSSL ON) + endif() +endif() + include(GNUInstallDirs) set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/crashpad") @@ -38,10 +49,6 @@ function(crashpad_install_dev) endif() endfunction() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(LINUX TRUE) -endif() - if(WIN32) enable_language(ASM_MASM) if(MINGW) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 14f3903131..68b9633910 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -400,15 +400,20 @@ if(LINUX) target_link_libraries(crashpad_util PRIVATE pthread) endif() +if(CRASHPAD_USE_BORINGSSL) + target_compile_definitions(crashpad_util PRIVATE CRASHPAD_USE_BORINGSSL) + target_link_libraries(crashpad_util PRIVATE OpenSSL::SSL OpenSSL::Crypto) +endif() + if(WIN32) target_link_libraries(crashpad_util PRIVATE user32 version winhttp) if(MSVC) target_compile_options(crashpad_util PRIVATE "/wd4201") elseif(MINGW) - target_compile_options(crashpad_util PRIVATE + target_compile_options(crashpad_util PRIVATE $<$:-municode> ) - target_compile_definitions(crashpad_util PRIVATE + target_compile_definitions(crashpad_util PRIVATE "__STDC_VERSION__=199901L" $<$:__MINGW32__> ) @@ -420,13 +425,15 @@ if(WIN32) "-include memory" ) endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_util PRIVATE - $<$:-Wno-multichar> - ) - endif() endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_util PRIVATE + $<$:-Wno-multichar> + ) +endif() + + set_property(TARGET crashpad_util PROPERTY EXPORT_NAME util) add_library(crashpad::util ALIAS crashpad_util) From f24aa826f4f7e9f90a41b028b5009d0f5b9cbe7d Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 1 Jul 2020 15:49:32 +0200 Subject: [PATCH 029/478] fix: Add a Host Header to the upload request (#17) This fixes https minidump uploads on linux. --- util/net/http_transport_socket.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index b9c6c9c5e0..d1c0194c18 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -328,11 +328,15 @@ base::ScopedFD CreateSocket(const std::string& hostname, bool WriteRequest(Stream* stream, const std::string& method, + const std::string& hostname, const std::string& resource, const HTTPHeaders& headers, HTTPBodyStream* body_stream) { - std::string request_line = base::StringPrintf( - "%s %s HTTP/1.0\r\n", method.c_str(), resource.c_str()); + std::string request_line = + base::StringPrintf("%s %s HTTP/1.0\r\nHost: %s\r\n", + method.c_str(), + resource.c_str(), + hostname.c_str()); if (!stream->LoggingWrite(request_line.data(), request_line.size())) return false; @@ -574,8 +578,12 @@ bool HTTPTransportSocket::ExecuteSynchronously(std::string* response_body) { std::unique_ptr stream(std::make_unique(sock.get())); #endif // CRASHPAD_USE_BORINGSSL - if (!WriteRequest( - stream.get(), method(), resource, headers(), body_stream())) { + if (!WriteRequest(stream.get(), + method(), + hostname, + resource, + headers(), + body_stream())) { return false; } From e6bcc27ffdeda51cb9f03f0bb117ac204c2c70d9 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 15 Jul 2020 12:38:33 +0200 Subject: [PATCH 030/478] ci: Run a simple CMake build on CI (#18) --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ client/CMakeLists.txt | 11 ++++++++--- handler/CMakeLists.txt | 13 +++++++------ minidump/CMakeLists.txt | 4 ++-- snapshot/CMakeLists.txt | 15 ++++++++++----- 5 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..3dd3c92123 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,23 @@ +name: Build + +on: + push: + branches: + - getsentry + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + with: + submodules: "recursive" + - uses: lukka/run-cmake@v2 + with: + cmakeListsOrSettingsJson: "CMakeListsTxtAdvanced" + buildWithCMakeArgs: "--parallel" diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index b1a77c1944..11ba9f4edc 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -79,12 +79,11 @@ if(WIN32) ) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_client PRIVATE - "-Wno-multichar" + target_compile_options(crashpad_client PRIVATE "-Wno-attributes" ) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_compile_options(crashpad_client PRIVATE + target_compile_options(crashpad_client PRIVATE "-Wno-unknown-attributes" "-Wno-unknown-pragmas" ) @@ -99,6 +98,12 @@ if(IOS) ) endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_client PRIVATE + "-Wno-multichar" + ) +endif() + crashpad_install_target(crashpad_client) crashpad_install_dev(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/client" diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index a0b5d2deeb..4d37ba936a 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -62,11 +62,12 @@ if(WIN32) if(MSVC) target_compile_options(crashpad_handler_lib PRIVATE "/wd4201") endif() - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_handler_lib PRIVATE - "-Wno-multichar" - ) - endif() +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_handler_lib PRIVATE + "-Wno-multichar" + ) endif() set_property(TARGET crashpad_handler_lib PROPERTY EXPORT_NAME handler) @@ -105,4 +106,4 @@ if(NOT IOS) install(TARGETS crashpad_handler EXPORT crashpad_export RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) -endif() \ No newline at end of file +endif() diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt index 83ed22f121..1bf972ab98 100644 --- a/minidump/CMakeLists.txt +++ b/minidump/CMakeLists.txt @@ -66,8 +66,8 @@ if(MSVC) target_compile_options(crashpad_minidump PRIVATE "/wd4201" "/wd4324") endif() -if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_minidump PRIVATE +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_minidump PRIVATE "-Wno-multichar" ) endif() diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index bc8ec7cf2c..5da894b76a 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -205,17 +205,22 @@ if(WIN32) target_compile_options(crashpad_snapshot PRIVATE "/wd4201") endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(crashpad_snapshot PRIVATE - "-Wno-multichar" + target_compile_options(crashpad_snapshot PRIVATE "-Wno-attributes" ) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_compile_options(crashpad_snapshot PRIVATE - "-Wno-unknown-attributes" - ) + target_compile_options(crashpad_snapshot PRIVATE + "-Wno-unknown-attributes" + ) endif() endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(crashpad_snapshot PRIVATE + "-Wno-multichar" + ) +endif() + set_property(TARGET crashpad_snapshot PROPERTY EXPORT_NAME snapshot) add_library(crashpad::snapshot ALIAS crashpad_snapshot) From 03abac256cde53f2c079097510edfb3bb275549b Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 21 Jul 2020 19:09:52 +0200 Subject: [PATCH 031/478] feat: Implement a FirstChanceHandler for Windows as well (#20) --- client/crashpad_client.h | 25 +++++++++++++++++++++++-- client/crashpad_client_linux.cc | 6 +++--- client/crashpad_client_win.cc | 12 ++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 6f8c2fe018..f9b8aa84dd 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -398,7 +398,7 @@ class CrashpadClient { static void CrashWithoutDump(const std::string& message); //! \brief The type for custom handlers installed by clients. - using FirstChanceHandler = bool (*)(int, siginfo_t*, ucontext_t*); + using FirstChanceHandlerLinux = bool (*)(int, siginfo_t*, ucontext_t*); //! \brief Installs a custom crash signal handler which runs before the //! currently installed Crashpad handler. @@ -416,7 +416,7 @@ class CrashpadClient { //! signal handler is run. //! //! \param[in] handler The custom crash signal handler to install. - static void SetFirstChanceExceptionHandler(FirstChanceHandler handler); + static void SetFirstChanceExceptionHandler(FirstChanceHandlerLinux handler); //! \brief Configures a set of signals that shouldn't have Crashpad signal //! handlers installed. @@ -501,6 +501,27 @@ class CrashpadClient { #endif #if defined(OS_WIN) || DOXYGEN + //! \brief The type for custom handlers installed by clients. + using FirstChanceHandlerWin = bool (*)(EXCEPTION_POINTERS*); + + //! \brief Installs a custom unhandled exception filter which runs before the + //! currently installed Crashpad handler. + //! + //! Handling exceptions appropriately can be tricky and use of this method + //! should be avoided, if possible. + //! + //! A handler must have already been installed before calling this method. + //! + //! The custom handler runs in an unhandled exception filter context and must + //! be safe for that purpose. + //! + //! If the custom handler returns `true`, the exception is considered handled + //! and the handler returns. Otherwise, the currently installed Crashpad + //! unhandled exception handler is run. + //! + //! \param[in] handler The custom unhandled exception handler to install. + static void SetFirstChanceExceptionHandler(FirstChanceHandlerWin handler); + //! \brief Sets the IPC pipe of a presumably-running Crashpad handler process //! which was started with StartHandler() or by other compatible means //! and does an IPC message exchange to register this process with the diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 4fb99d846f..af4c7969a6 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -132,7 +132,7 @@ class SignalHandler { // handler will be restored and the signal reraised. static void DisableForThread() { disabled_for_thread_ = true; } - void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { + void SetFirstChanceHandler(CrashpadClient::FirstChanceHandlerLinux handler) { first_chance_handler_ = handler; } @@ -193,7 +193,7 @@ class SignalHandler { Signals::OldActions old_actions_ = {}; ExceptionInformation exception_information_ = {}; - CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; + CrashpadClient::FirstChanceHandlerLinux first_chance_handler_ = nullptr; static SignalHandler* handler_; @@ -566,7 +566,7 @@ void CrashpadClient::CrashWithoutDump(const std::string& message) { // static void CrashpadClient::SetFirstChanceExceptionHandler( - FirstChanceHandler handler) { + FirstChanceHandlerLinux handler) { DCHECK(SignalHandler::Get()); SignalHandler::Get()->SetFirstChanceHandler(handler); } diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 1f2fb819d0..486db54934 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -68,6 +68,8 @@ ExceptionInformation g_crash_exception_information; HANDLE g_signal_non_crash_dump = INVALID_HANDLE_VALUE; HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; +CrashpadClient::FirstChanceHandlerWin first_chance_handler_ = nullptr; + // Guards multiple simultaneous calls to DumpWithoutCrash(). This is leaked. base::Lock* g_non_crash_dump_lock; @@ -134,6 +136,10 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { return EXCEPTION_CONTINUE_SEARCH; } + if (first_chance_handler_ && first_chance_handler_(exception_pointers)) { + return EXCEPTION_CONTINUE_SEARCH; + } + // Otherwise, we know the handler startup has succeeded, and we can continue. // Tracks whether a thread has already entered UnhandledExceptionHandler. @@ -1070,4 +1076,10 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process, return result; } +// static +void CrashpadClient::SetFirstChanceExceptionHandler( + FirstChanceHandlerWin handler) { + first_chance_handler_ = handler; +} + } // namespace crashpad From da9a6485b8fd7c9bc5dade452c2f50cd93153cda Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 3 Aug 2020 09:50:00 +0200 Subject: [PATCH 032/478] build: Update submodule and linux handler --- handler/CMakeLists.txt | 6 ++++++ third_party/mini_chromium/mini_chromium | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 4d37ba936a..181efa510e 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -80,6 +80,12 @@ if(NOT IOS) main.cc ) + if(LINUX) + target_sources(crashpad_handler PRIVATE + ../client/pthread_create_linux.cc + ) + endif() + target_link_libraries(crashpad_handler PRIVATE $ diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 4e8ff0c3a2..891e31d0b6 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 4e8ff0c3a29fe33b7b99bcd02ca3b53fa98143ac +Subproject commit 891e31d0b649ec9fa98ca5745f9dcd14a34de34c From a0b37e180de96fb1dd22a26ce1bc847f4dd21824 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 2 Nov 2020 16:24:18 +0100 Subject: [PATCH 033/478] feat: CMake build support for iOS (#27) --- .github/workflows/build.yml | 10 ++++++++++ handler/CMakeLists.txt | 2 +- util/CMakeLists.txt | 23 +++++++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3dd3c92123..a5211b0776 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,3 +21,13 @@ jobs: with: cmakeListsOrSettingsJson: "CMakeListsTxtAdvanced" buildWithCMakeArgs: "--parallel" + + build-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: "recursive" + - run: | + cmake -B crashpad-xcode -GXcode -DCMAKE_SYSTEM_NAME=iOS + xcodebuild build -project crashpad-xcode/crashpad.xcodeproj diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 181efa510e..3288ac46b2 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(crashpad_handler_lib STATIC user_stream_data_source.h ) -if(APPLE) +if(APPLE AND NOT IOS) target_sources(crashpad_handler_lib PRIVATE mac/crash_report_exception_handler.cc mac/crash_report_exception_handler.h diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 90cc5c241a..7a3425f8da 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -334,7 +334,7 @@ if(APPLE) if(NOT IOS) set(def_relative_files "exc.defs" "mach_exc.defs" "notify.defs") set(input_files "${CMAKE_CURRENT_LIST_DIR}/mach/child_port.defs") - elseif() + else() set(def_relative_files "") set(input_files "${CMAKE_CURRENT_LIST_DIR}/../third_party/xnu/osfmk/mach/exc.defs" @@ -356,6 +356,25 @@ if(APPLE) set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/util/mach") file(MAKE_DIRECTORY "${output_dir}") + get_property(archs TARGET crashpad_util PROPERTY OSX_ARCHITECTURES) + if(NOT archs) + if(IOS) + set(archs "arm64") + else() + set(archs "x86_64") + endif() + endif() + list(TRANSFORM archs PREPEND "--arch=") + + set(includes + "${CMAKE_CURRENT_SOURCE_DIR}/.." + "${CMAKE_CURRENT_SOURCE_DIR}/../compat/mac" + ) + if(IOS) + list(APPEND includes "${CMAKE_CURRENT_SOURCE_DIR}/../compat/ios") + endif() + list(TRANSFORM includes PREPEND "--include=") + # Create generate rule for each input file. Add each generated output # as a source to the target. foreach(input ${input_files}) @@ -368,7 +387,7 @@ if(APPLE) OUTPUT ${output_files} COMMAND - "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ${output_files} + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" ${archs} ${includes} "${input}" ${output_files} DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ) From fba97d0d5556ebd2dc94d183304ff990d2462820 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 4 Nov 2020 11:41:27 +0100 Subject: [PATCH 034/478] fix: Silence new MSVC warning in zlib (#28) --- third_party/zlib/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index 7ed2f58680..451433171f 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -73,6 +73,7 @@ else() "/wd4267" # conversion from 'size_t' to 't', possible loss of data "/wd4324" # structure was padded due to alignment specifier "/wd4702" # unreachable code + "/wd5105" # see https://github.com/getsentry/sentry-native/issues/415 ) endif() endif() From 4e586713187add7ac504e157bf2ccec7b0bd1eaa Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 21 Dec 2020 20:58:34 +0100 Subject: [PATCH 035/478] meta: Update Crashpad to 2020-12-21 (#29) --- BUILD.gn | 13 - DEPS | 4 +- build/ios/setup_ios_gn.py | 1 - minidump/BUILD.gn | 2 - minidump/minidump_exception_writer_test.cc | 31 ++- minidump/minidump_handle_writer_test.cc | 65 +++-- minidump/minidump_memory_info_writer_test.cc | 31 ++- minidump/minidump_misc_info_writer_test.cc | 27 +- minidump/minidump_module_writer_test.cc | 95 ++++--- minidump/minidump_system_info_writer_test.cc | 23 +- minidump/minidump_thread_writer_test.cc | 48 ++-- .../test/minidump_memory_writer_test_util.cc | 18 +- snapshot/BUILD.gn | 4 +- snapshot/linux/debug_rendezvous.h | 2 +- snapshot/linux/debug_rendezvous_test.cc | 44 ++- snapshot/linux/process_reader_linux_test.cc | 223 +-------------- snapshot/linux/test_modules.cc | 262 ++++++++++++++++++ snapshot/linux/test_modules.h | 37 +++ .../minidump/process_snapshot_minidump.cc | 2 +- snapshot/snapshot_test.gyp | 2 + test/fuchsia_crashpad_tests.cmx | 3 + third_party/edo/BUILD.gn | 4 +- third_party/googletest/BUILD.gn | 1 - third_party/lss/README.crashpad | 2 +- third_party/mini_chromium/mini_chromium | 2 +- util/BUILD.gn | 3 +- util/file/file_io.cc | 14 +- util/linux/initial_signal_dispositions.cc | 3 +- util/linux/ptrace_broker.cc | 110 ++++---- util/linux/ptrace_broker.h | 13 +- util/linux/scoped_ptrace_attach.cc | 43 ++- util/linux/scoped_ptrace_attach.h | 18 ++ util/net/http_transport_socket.cc | 2 +- util/posix/scoped_mmap.cc | 71 ++++- util/posix/scoped_mmap.h | 6 +- util/stdlib/aligned_allocator.h | 2 +- 36 files changed, 746 insertions(+), 485 deletions(-) create mode 100644 snapshot/linux/test_modules.cc create mode 100644 snapshot/linux/test_modules.h diff --git a/BUILD.gn b/BUILD.gn index 7c0a794096..1ec9b97538 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -20,19 +20,6 @@ config("crashpad_config") { include_dirs = [ "." ] } -# TODO(fuchsia:46805): Remove this once instances of UB have been cleaned up. -config("disable_ubsan") { - if (crashpad_is_in_fuchsia) { - cflags = [ "-fno-sanitize=undefined" ] - } - visibility = [ - "snapshot:snapshot", - "minidump:minidump_test", - "third_party/googletest:googletest", - "util:util", - ] -} - if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ diff --git a/DEPS b/DEPS index fbff15550a..db8fd8d514 100644 --- a/DEPS +++ b/DEPS @@ -28,7 +28,7 @@ deps = { '9e121212d42be62a7cce38072f925f8398d11e49', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + - '97121c64019fa0e8bfbc8254e3ccb5572c500746', + '6ffbf833173f53fcd06ecf08670a95cc01c01f72', 'condition': 'checkout_ios', }, 'crashpad/third_party/googletest/googletest': @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'cb82d71291f19590d3ee138ba64fcf1e9e0edd84', + 'c748b289b825056985f3dd3b36dc86c766d787ad', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/build/ios/setup_ios_gn.py b/build/ios/setup_ios_gn.py index 5f1829ee20..9522ce6757 100755 --- a/build/ios/setup_ios_gn.py +++ b/build/ios/setup_ios_gn.py @@ -199,7 +199,6 @@ def GetGnCommand(self, gn_path, src_path, out_path, generate_xcode_project): gn_command = [gn_path, '--root=%s' % os.path.realpath(src_path), '-q'] if generate_xcode_project: gn_command.append('--ide=xcode') - gn_command.append('--root-target=gn_all') gn_command.append('--ninja-executable=autoninja') if self._settings.has_section('filters'): target_filters = self._settings.values('filters') diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index 6217edebd6..459fd6b751 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -186,6 +186,4 @@ source_set("minidump_test") { if (crashpad_is_win) { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } - - configs += [ "..:disable_ubsan" ] } diff --git a/minidump/minidump_exception_writer_test.cc b/minidump/minidump_exception_writer_test.cc index eed8f104b5..72837bba93 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -69,22 +69,27 @@ void ExpectExceptionStream(const MINIDUMP_EXCEPTION_STREAM* expected, const MinidumpContextX86** context) { EXPECT_EQ(observed->ThreadId, expected->ThreadId); EXPECT_EQ(observed->__alignment, 0u); - EXPECT_EQ(observed->ExceptionRecord.ExceptionCode, - expected->ExceptionRecord.ExceptionCode); - EXPECT_EQ(observed->ExceptionRecord.ExceptionFlags, - expected->ExceptionRecord.ExceptionFlags); - EXPECT_EQ(observed->ExceptionRecord.ExceptionRecord, - expected->ExceptionRecord.ExceptionRecord); - EXPECT_EQ(observed->ExceptionRecord.ExceptionAddress, - expected->ExceptionRecord.ExceptionAddress); - EXPECT_EQ(observed->ExceptionRecord.NumberParameters, - expected->ExceptionRecord.NumberParameters); + + // Copy the ExceptionRecords so that their uint64_t members can be accessed + // with the proper alignment. + const MINIDUMP_EXCEPTION observed_exception = observed->ExceptionRecord; + const MINIDUMP_EXCEPTION expected_exception = expected->ExceptionRecord; + + EXPECT_EQ(observed_exception.ExceptionCode, expected_exception.ExceptionCode); + EXPECT_EQ(observed_exception.ExceptionFlags, + expected_exception.ExceptionFlags); + EXPECT_EQ(observed_exception.ExceptionRecord, + expected_exception.ExceptionRecord); + EXPECT_EQ(observed_exception.ExceptionAddress, + expected_exception.ExceptionAddress); + EXPECT_EQ(observed_exception.NumberParameters, + expected_exception.NumberParameters); EXPECT_EQ(observed->ExceptionRecord.__unusedAlignment, 0u); for (size_t index = 0; - index < base::size(observed->ExceptionRecord.ExceptionInformation); + index < base::size(observed_exception.ExceptionInformation); ++index) { - EXPECT_EQ(observed->ExceptionRecord.ExceptionInformation[index], - expected->ExceptionRecord.ExceptionInformation[index]); + EXPECT_EQ(observed_exception.ExceptionInformation[index], + expected_exception.ExceptionInformation[index]); } *context = MinidumpWritableAtLocationDescriptor( file_contents, observed->ThreadContext); diff --git a/minidump/minidump_handle_writer_test.cc b/minidump/minidump_handle_writer_test.cc index 19a1036bd4..0776ae02c4 100644 --- a/minidump/minidump_handle_writer_test.cc +++ b/minidump/minidump_handle_writer_test.cc @@ -110,18 +110,17 @@ TEST(MinidumpHandleDataWriter, OneHandle) { GetHandleDataStream(string_file.string(), &handle_data_stream)); EXPECT_EQ(handle_data_stream->NumberOfDescriptors, 1u); - const MINIDUMP_HANDLE_DESCRIPTOR* handle_descriptor = - reinterpret_cast( - &handle_data_stream[1]); - EXPECT_EQ(handle_descriptor->Handle, handle_snapshot.handle); + MINIDUMP_HANDLE_DESCRIPTOR handle_descriptor; + memcpy(&handle_descriptor, &handle_data_stream[1], sizeof(handle_descriptor)); + EXPECT_EQ(handle_descriptor.Handle, handle_snapshot.handle); EXPECT_EQ(base::UTF16ToUTF8(MinidumpStringAtRVAAsString( - string_file.string(), handle_descriptor->TypeNameRva)), + string_file.string(), handle_descriptor.TypeNameRva)), handle_snapshot.type_name); - EXPECT_EQ(handle_descriptor->ObjectNameRva, 0u); - EXPECT_EQ(handle_descriptor->Attributes, handle_snapshot.attributes); - EXPECT_EQ(handle_descriptor->GrantedAccess, handle_snapshot.granted_access); - EXPECT_EQ(handle_descriptor->HandleCount, handle_snapshot.handle_count); - EXPECT_EQ(handle_descriptor->PointerCount, handle_snapshot.pointer_count); + EXPECT_EQ(handle_descriptor.ObjectNameRva, 0u); + EXPECT_EQ(handle_descriptor.Attributes, handle_snapshot.attributes); + EXPECT_EQ(handle_descriptor.GrantedAccess, handle_snapshot.granted_access); + EXPECT_EQ(handle_descriptor.HandleCount, handle_snapshot.handle_count); + EXPECT_EQ(handle_descriptor.PointerCount, handle_snapshot.pointer_count); } TEST(MinidumpHandleDataWriter, RepeatedTypeName) { @@ -168,34 +167,34 @@ TEST(MinidumpHandleDataWriter, RepeatedTypeName) { GetHandleDataStream(string_file.string(), &handle_data_stream)); EXPECT_EQ(handle_data_stream->NumberOfDescriptors, 2u); - const MINIDUMP_HANDLE_DESCRIPTOR* handle_descriptor = - reinterpret_cast( - &handle_data_stream[1]); - EXPECT_EQ(handle_descriptor->Handle, handle_snapshot.handle); + MINIDUMP_HANDLE_DESCRIPTOR handle_descriptor; + memcpy(&handle_descriptor, &handle_data_stream[1], sizeof(handle_descriptor)); + EXPECT_EQ(handle_descriptor.Handle, handle_snapshot.handle); EXPECT_EQ(base::UTF16ToUTF8(MinidumpStringAtRVAAsString( - string_file.string(), handle_descriptor->TypeNameRva)), + string_file.string(), handle_descriptor.TypeNameRva)), handle_snapshot.type_name); - EXPECT_EQ(handle_descriptor->ObjectNameRva, 0u); - EXPECT_EQ(handle_descriptor->Attributes, handle_snapshot.attributes); - EXPECT_EQ(handle_descriptor->GrantedAccess, handle_snapshot.granted_access); - EXPECT_EQ(handle_descriptor->HandleCount, handle_snapshot.handle_count); - EXPECT_EQ(handle_descriptor->PointerCount, handle_snapshot.pointer_count); - - const MINIDUMP_HANDLE_DESCRIPTOR* handle_descriptor2 = - reinterpret_cast( - reinterpret_cast(&handle_data_stream[1]) + - sizeof(MINIDUMP_HANDLE_DESCRIPTOR)); - EXPECT_EQ(handle_descriptor2->Handle, handle_snapshot2.handle); + EXPECT_EQ(handle_descriptor.ObjectNameRva, 0u); + EXPECT_EQ(handle_descriptor.Attributes, handle_snapshot.attributes); + EXPECT_EQ(handle_descriptor.GrantedAccess, handle_snapshot.granted_access); + EXPECT_EQ(handle_descriptor.HandleCount, handle_snapshot.handle_count); + EXPECT_EQ(handle_descriptor.PointerCount, handle_snapshot.pointer_count); + + MINIDUMP_HANDLE_DESCRIPTOR handle_descriptor2; + memcpy(&handle_descriptor2, + reinterpret_cast(&handle_data_stream[1]) + + sizeof(MINIDUMP_HANDLE_DESCRIPTOR), + sizeof(handle_descriptor2)); + EXPECT_EQ(handle_descriptor2.Handle, handle_snapshot2.handle); EXPECT_EQ(base::UTF16ToUTF8(MinidumpStringAtRVAAsString( - string_file.string(), handle_descriptor2->TypeNameRva)), + string_file.string(), handle_descriptor2.TypeNameRva)), handle_snapshot2.type_name); - EXPECT_EQ(handle_descriptor2->ObjectNameRva, 0u); - EXPECT_EQ(handle_descriptor2->Attributes, handle_snapshot2.attributes); - EXPECT_EQ(handle_descriptor2->GrantedAccess, handle_snapshot2.granted_access); - EXPECT_EQ(handle_descriptor2->HandleCount, handle_snapshot2.handle_count); - EXPECT_EQ(handle_descriptor2->PointerCount, handle_snapshot2.pointer_count); + EXPECT_EQ(handle_descriptor2.ObjectNameRva, 0u); + EXPECT_EQ(handle_descriptor2.Attributes, handle_snapshot2.attributes); + EXPECT_EQ(handle_descriptor2.GrantedAccess, handle_snapshot2.granted_access); + EXPECT_EQ(handle_descriptor2.HandleCount, handle_snapshot2.handle_count); + EXPECT_EQ(handle_descriptor2.PointerCount, handle_snapshot2.pointer_count); - EXPECT_EQ(handle_descriptor2->TypeNameRva, handle_descriptor->TypeNameRva); + EXPECT_EQ(handle_descriptor2.TypeNameRva, handle_descriptor.TypeNameRva); } } // namespace diff --git a/minidump/minidump_memory_info_writer_test.cc b/minidump/minidump_memory_info_writer_test.cc index 634d3f1af1..e45ea57330 100644 --- a/minidump/minidump_memory_info_writer_test.cc +++ b/minidump/minidump_memory_info_writer_test.cc @@ -74,7 +74,11 @@ TEST(MinidumpMemoryInfoWriter, Empty) { ASSERT_NO_FATAL_FAILURE( GetMemoryInfoListStream(string_file.string(), &memory_info_list)); - EXPECT_EQ(memory_info_list->NumberOfEntries, 0u); + uint64_t number_of_entries; + memcpy(&number_of_entries, + &memory_info_list->NumberOfEntries, + sizeof(number_of_entries)); + EXPECT_EQ(number_of_entries, 0u); } TEST(MinidumpMemoryInfoWriter, OneRegion) { @@ -115,16 +119,21 @@ TEST(MinidumpMemoryInfoWriter, OneRegion) { ASSERT_NO_FATAL_FAILURE( GetMemoryInfoListStream(string_file.string(), &memory_info_list)); - EXPECT_EQ(memory_info_list->NumberOfEntries, 1u); - const MINIDUMP_MEMORY_INFO* memory_info = - reinterpret_cast(&memory_info_list[1]); - EXPECT_EQ(memory_info->BaseAddress, mmi.BaseAddress); - EXPECT_EQ(memory_info->AllocationBase, mmi.AllocationBase); - EXPECT_EQ(memory_info->AllocationProtect, mmi.AllocationProtect); - EXPECT_EQ(memory_info->RegionSize, mmi.RegionSize); - EXPECT_EQ(memory_info->State, mmi.State); - EXPECT_EQ(memory_info->Protect, mmi.Protect); - EXPECT_EQ(memory_info->Type, mmi.Type); + uint64_t number_of_entries; + memcpy(&number_of_entries, + &memory_info_list->NumberOfEntries, + sizeof(number_of_entries)); + EXPECT_EQ(number_of_entries, 1u); + + MINIDUMP_MEMORY_INFO memory_info; + memcpy(&memory_info, &memory_info_list[1], sizeof(memory_info)); + EXPECT_EQ(memory_info.BaseAddress, mmi.BaseAddress); + EXPECT_EQ(memory_info.AllocationBase, mmi.AllocationBase); + EXPECT_EQ(memory_info.AllocationProtect, mmi.AllocationProtect); + EXPECT_EQ(memory_info.RegionSize, mmi.RegionSize); + EXPECT_EQ(memory_info.State, mmi.State); + EXPECT_EQ(memory_info.Protect, mmi.Protect); + EXPECT_EQ(memory_info.Type, mmi.Type); } } // namespace diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index b7ea3d041a..7e93fc5f6d 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -171,20 +171,27 @@ void ExpectMiscInfoEqual( ExpectMiscInfoEqual( reinterpret_cast(expected), reinterpret_cast(observed)); - EXPECT_EQ(observed->XStateData.SizeOfInfo, expected->XStateData.SizeOfInfo); - EXPECT_EQ(observed->XStateData.ContextSize, expected->XStateData.ContextSize); - EXPECT_EQ(observed->XStateData.EnabledFeatures, - expected->XStateData.EnabledFeatures); + + MINIDUMP_MISC_INFO_5 expected_misc_info, observed_misc_info; + memcpy(&expected_misc_info, expected, sizeof(expected_misc_info)); + memcpy(&observed_misc_info, observed, sizeof(observed_misc_info)); + + EXPECT_EQ(observed_misc_info.XStateData.SizeOfInfo, + expected_misc_info.XStateData.SizeOfInfo); + EXPECT_EQ(observed_misc_info.XStateData.ContextSize, + expected_misc_info.XStateData.ContextSize); + EXPECT_EQ(observed_misc_info.XStateData.EnabledFeatures, + expected_misc_info.XStateData.EnabledFeatures); for (size_t feature_index = 0; - feature_index < base::size(observed->XStateData.Features); + feature_index < base::size(observed_misc_info.XStateData.Features); ++feature_index) { SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index)); - EXPECT_EQ(observed->XStateData.Features[feature_index].Offset, - expected->XStateData.Features[feature_index].Offset); - EXPECT_EQ(observed->XStateData.Features[feature_index].Size, - expected->XStateData.Features[feature_index].Size); + EXPECT_EQ(observed_misc_info.XStateData.Features[feature_index].Offset, + expected_misc_info.XStateData.Features[feature_index].Offset); + EXPECT_EQ(observed_misc_info.XStateData.Features[feature_index].Size, + expected_misc_info.XStateData.Features[feature_index].Size); } - EXPECT_EQ(observed->ProcessCookie, expected->ProcessCookie); + EXPECT_EQ(observed_misc_info.ProcessCookie, expected_misc_info.ProcessCookie); } TEST(MinidumpMiscInfoWriter, Empty) { diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 71db3ac171..e40d1af1a9 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -213,56 +213,68 @@ void ExpectModule(const MINIDUMP_MODULE* expected, const char* expected_debug_name, uint32_t expected_debug_type, bool expected_debug_utf16) { - EXPECT_EQ(observed->BaseOfImage, expected->BaseOfImage); - EXPECT_EQ(observed->SizeOfImage, expected->SizeOfImage); - EXPECT_EQ(observed->CheckSum, expected->CheckSum); - EXPECT_EQ(observed->TimeDateStamp, expected->TimeDateStamp); - EXPECT_EQ(observed->VersionInfo.dwSignature, + MINIDUMP_MODULE expected_module, observed_module; + memcpy(&expected_module, expected, sizeof(expected_module)); + memcpy(&observed_module, observed, sizeof(observed_module)); + + EXPECT_EQ(observed_module.BaseOfImage, expected_module.BaseOfImage); + EXPECT_EQ(observed_module.SizeOfImage, expected_module.SizeOfImage); + EXPECT_EQ(observed_module.CheckSum, expected_module.CheckSum); + EXPECT_EQ(observed_module.TimeDateStamp, expected_module.TimeDateStamp); + EXPECT_EQ(observed_module.VersionInfo.dwSignature, implicit_cast(VS_FFI_SIGNATURE)); - EXPECT_EQ(observed->VersionInfo.dwStrucVersion, + EXPECT_EQ(observed_module.VersionInfo.dwStrucVersion, implicit_cast(VS_FFI_STRUCVERSION)); - EXPECT_EQ(observed->VersionInfo.dwFileVersionMS, - expected->VersionInfo.dwFileVersionMS); - EXPECT_EQ(observed->VersionInfo.dwFileVersionLS, - expected->VersionInfo.dwFileVersionLS); - EXPECT_EQ(observed->VersionInfo.dwProductVersionMS, - expected->VersionInfo.dwProductVersionMS); - EXPECT_EQ(observed->VersionInfo.dwProductVersionLS, - expected->VersionInfo.dwProductVersionLS); - EXPECT_EQ(observed->VersionInfo.dwFileFlagsMask, - expected->VersionInfo.dwFileFlagsMask); - EXPECT_EQ(observed->VersionInfo.dwFileFlags, - expected->VersionInfo.dwFileFlags); - EXPECT_EQ(observed->VersionInfo.dwFileOS, expected->VersionInfo.dwFileOS); - EXPECT_EQ(observed->VersionInfo.dwFileType, expected->VersionInfo.dwFileType); - EXPECT_EQ(observed->VersionInfo.dwFileSubtype, - expected->VersionInfo.dwFileSubtype); - EXPECT_EQ(observed->VersionInfo.dwFileDateMS, - expected->VersionInfo.dwFileDateMS); - EXPECT_EQ(observed->VersionInfo.dwFileDateLS, - expected->VersionInfo.dwFileDateLS); - EXPECT_EQ(observed->Reserved0, 0u); - EXPECT_EQ(observed->Reserved1, 0u); - - EXPECT_NE(observed->ModuleNameRva, 0u); + EXPECT_EQ(observed_module.VersionInfo.dwFileVersionMS, + expected_module.VersionInfo.dwFileVersionMS); + EXPECT_EQ(observed_module.VersionInfo.dwFileVersionLS, + expected_module.VersionInfo.dwFileVersionLS); + EXPECT_EQ(observed_module.VersionInfo.dwProductVersionMS, + expected_module.VersionInfo.dwProductVersionMS); + EXPECT_EQ(observed_module.VersionInfo.dwProductVersionLS, + expected_module.VersionInfo.dwProductVersionLS); + EXPECT_EQ(observed_module.VersionInfo.dwFileFlagsMask, + expected_module.VersionInfo.dwFileFlagsMask); + EXPECT_EQ(observed_module.VersionInfo.dwFileFlags, + expected_module.VersionInfo.dwFileFlags); + EXPECT_EQ(observed_module.VersionInfo.dwFileOS, + expected_module.VersionInfo.dwFileOS); + EXPECT_EQ(observed_module.VersionInfo.dwFileType, + expected_module.VersionInfo.dwFileType); + EXPECT_EQ(observed_module.VersionInfo.dwFileSubtype, + expected_module.VersionInfo.dwFileSubtype); + EXPECT_EQ(observed_module.VersionInfo.dwFileDateMS, + expected_module.VersionInfo.dwFileDateMS); + EXPECT_EQ(observed_module.VersionInfo.dwFileDateLS, + expected_module.VersionInfo.dwFileDateLS); + + uint64_t reserved0, reserved1; + memcpy(&reserved0, &observed_module.Reserved0, sizeof(reserved0)); + memcpy(&reserved1, &observed_module.Reserved1, sizeof(reserved1)); + + EXPECT_EQ(reserved0, 0u); + EXPECT_EQ(reserved1, 0u); + + EXPECT_NE(observed_module.ModuleNameRva, 0u); base::string16 observed_module_name_utf16 = - MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva); + MinidumpStringAtRVAAsString(file_contents, observed_module.ModuleNameRva); base::string16 expected_module_name_utf16 = base::UTF8ToUTF16(expected_module_name); EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16); - ASSERT_NO_FATAL_FAILURE(ExpectCodeViewRecord(&observed->CvRecord, + ASSERT_NO_FATAL_FAILURE(ExpectCodeViewRecord(&observed_module.CvRecord, file_contents, expected_pdb_name, expected_pdb_uuid, expected_pdb_timestamp, expected_pdb_age)); - ASSERT_NO_FATAL_FAILURE(ExpectMiscellaneousDebugRecord(&observed->MiscRecord, - file_contents, - expected_debug_name, - expected_debug_type, - expected_debug_utf16)); + ASSERT_NO_FATAL_FAILURE( + ExpectMiscellaneousDebugRecord(&observed_module.MiscRecord, + file_contents, + expected_debug_name, + expected_debug_type, + expected_debug_utf16)); } // ExpectModuleWithBuildIDCv() is like ExpectModule( but expects the module to @@ -300,8 +312,13 @@ void ExpectModuleWithBuildIDCv(const MINIDUMP_MODULE* expected, expected->VersionInfo.dwFileDateMS); EXPECT_EQ(observed->VersionInfo.dwFileDateLS, expected->VersionInfo.dwFileDateLS); - EXPECT_EQ(observed->Reserved0, 0u); - EXPECT_EQ(observed->Reserved1, 0u); + + uint64_t reserved0, reserved1; + memcpy(&reserved0, &observed->Reserved0, sizeof(reserved0)); + memcpy(&reserved1, &observed->Reserved1, sizeof(reserved1)); + + EXPECT_EQ(reserved0, 0u); + EXPECT_EQ(reserved1, 0u); EXPECT_NE(observed->ModuleNameRva, 0u); base::string16 observed_module_name_utf16 = diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 99c599c14c..206a8e41cc 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -109,8 +109,11 @@ TEST(MinidumpSystemInfoWriter, Empty) { EXPECT_EQ(system_info->Cpu.X86CpuInfo.VersionInformation, 0u); EXPECT_EQ(system_info->Cpu.X86CpuInfo.FeatureInformation, 0u); EXPECT_EQ(system_info->Cpu.X86CpuInfo.AMDExtendedCpuFeatures, 0u); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[0], 0u); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[1], 0u); + + CPU_INFORMATION other_cpu_info; + memcpy(&other_cpu_info, &system_info->Cpu, sizeof(other_cpu_info)); + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[0], 0u); + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[1], 0u); EXPECT_EQ(csd_version->Buffer[0], '\0'); } @@ -234,10 +237,11 @@ TEST(MinidumpSystemInfoWriter, AMD64_Mac) { EXPECT_EQ(system_info->BuildNumber, kOSVersionBuild); EXPECT_EQ(system_info->PlatformId, kOS); EXPECT_EQ(system_info->SuiteMask, 0u); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[0], - kCPUFeatures[0]); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[1], - kCPUFeatures[1]); + + CPU_INFORMATION other_cpu_info; + memcpy(&other_cpu_info, &system_info->Cpu, sizeof(other_cpu_info)); + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[0], kCPUFeatures[0]); + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[1], kCPUFeatures[1]); } TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) { @@ -457,9 +461,12 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) { EXPECT_EQ(system_info->BuildNumber, expect_system_info.BuildNumber); EXPECT_EQ(system_info->PlatformId, expect_system_info.PlatformId); EXPECT_EQ(system_info->SuiteMask, expect_system_info.SuiteMask); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[0], + + CPU_INFORMATION other_cpu_info; + memcpy(&other_cpu_info, &system_info->Cpu, sizeof(other_cpu_info)); + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[0], expect_system_info.Cpu.OtherCpuInfo.ProcessorFeatures[0]); - EXPECT_EQ(system_info->Cpu.OtherCpuInfo.ProcessorFeatures[1], + EXPECT_EQ(other_cpu_info.OtherCpuInfo.ProcessorFeatures[1], expect_system_info.Cpu.OtherCpuInfo.ProcessorFeatures[1]); for (size_t index = 0; index < strlen(kOSVersionBuild); ++index) { diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc index e682b53d2d..3f3d56e830 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -108,33 +108,41 @@ void ExpectThread(const MINIDUMP_THREAD* expected, const std::string& file_contents, const MINIDUMP_MEMORY_DESCRIPTOR** stack, const void** context_base) { - EXPECT_EQ(observed->ThreadId, expected->ThreadId); - EXPECT_EQ(observed->SuspendCount, expected->SuspendCount); - EXPECT_EQ(observed->PriorityClass, expected->PriorityClass); - EXPECT_EQ(observed->Priority, expected->Priority); - EXPECT_EQ(observed->Teb, expected->Teb); - - EXPECT_EQ(observed->Stack.StartOfMemoryRange, - expected->Stack.StartOfMemoryRange); - EXPECT_EQ(observed->Stack.Memory.DataSize, expected->Stack.Memory.DataSize); + MINIDUMP_THREAD expected_thread, observed_thread; + memcpy(&expected_thread, expected, sizeof(expected_thread)); + memcpy(&observed_thread, observed, sizeof(observed_thread)); + + EXPECT_EQ(observed_thread.ThreadId, expected_thread.ThreadId); + EXPECT_EQ(observed_thread.SuspendCount, expected_thread.SuspendCount); + EXPECT_EQ(observed_thread.PriorityClass, expected_thread.PriorityClass); + EXPECT_EQ(observed_thread.Priority, expected_thread.Priority); + EXPECT_EQ(observed_thread.Teb, expected_thread.Teb); + + EXPECT_EQ(observed_thread.Stack.StartOfMemoryRange, + expected_thread.Stack.StartOfMemoryRange); + EXPECT_EQ(observed_thread.Stack.Memory.DataSize, + expected_thread.Stack.Memory.DataSize); if (stack) { - ASSERT_NE(observed->Stack.Memory.DataSize, 0u); - ASSERT_NE(observed->Stack.Memory.Rva, 0u); + ASSERT_NE(observed_thread.Stack.Memory.DataSize, 0u); + ASSERT_NE(observed_thread.Stack.Memory.Rva, 0u); ASSERT_GE(file_contents.size(), - observed->Stack.Memory.Rva + observed->Stack.Memory.DataSize); + observed_thread.Stack.Memory.Rva + + observed_thread.Stack.Memory.DataSize); *stack = &observed->Stack; } else { - EXPECT_EQ(observed->Stack.StartOfMemoryRange, 0u); - EXPECT_EQ(observed->Stack.Memory.DataSize, 0u); - EXPECT_EQ(observed->Stack.Memory.Rva, 0u); + EXPECT_EQ(observed_thread.Stack.StartOfMemoryRange, 0u); + EXPECT_EQ(observed_thread.Stack.Memory.DataSize, 0u); + EXPECT_EQ(observed_thread.Stack.Memory.Rva, 0u); } - EXPECT_EQ(observed->ThreadContext.DataSize, expected->ThreadContext.DataSize); - ASSERT_NE(observed->ThreadContext.DataSize, 0u); - ASSERT_NE(observed->ThreadContext.Rva, 0u); + EXPECT_EQ(observed_thread.ThreadContext.DataSize, + expected_thread.ThreadContext.DataSize); + ASSERT_NE(observed_thread.ThreadContext.DataSize, 0u); + ASSERT_NE(observed_thread.ThreadContext.Rva, 0u); ASSERT_GE(file_contents.size(), - observed->ThreadContext.Rva + expected->ThreadContext.DataSize); - *context_base = &file_contents[observed->ThreadContext.Rva]; + observed_thread.ThreadContext.Rva + + expected_thread.ThreadContext.DataSize); + *context_base = &file_contents[observed_thread.ThreadContext.Rva]; } TEST(MinidumpThreadWriter, OneThread_x86_NoStack) { diff --git a/minidump/test/minidump_memory_writer_test_util.cc b/minidump/test/minidump_memory_writer_test_util.cc index f198abebd9..4e38cfa638 100644 --- a/minidump/test/minidump_memory_writer_test_util.cc +++ b/minidump/test/minidump_memory_writer_test_util.cc @@ -38,12 +38,20 @@ void TestMinidumpMemoryWriter::SetShouldFailRead(bool should_fail) { void ExpectMinidumpMemoryDescriptor( const MINIDUMP_MEMORY_DESCRIPTOR* expected, const MINIDUMP_MEMORY_DESCRIPTOR* observed) { - EXPECT_EQ(observed->StartOfMemoryRange, expected->StartOfMemoryRange); - EXPECT_EQ(observed->Memory.DataSize, expected->Memory.DataSize); - if (expected->Memory.Rva != 0) { + MINIDUMP_MEMORY_DESCRIPTOR expected_descriptor; + MINIDUMP_MEMORY_DESCRIPTOR observed_descriptor; + + memcpy(&expected_descriptor, expected, sizeof(expected_descriptor)); + memcpy(&observed_descriptor, observed, sizeof(observed_descriptor)); + + EXPECT_EQ(observed_descriptor.StartOfMemoryRange, + expected_descriptor.StartOfMemoryRange); + EXPECT_EQ(observed_descriptor.Memory.DataSize, + expected_descriptor.Memory.DataSize); + if (expected_descriptor.Memory.Rva != 0) { constexpr uint32_t kMemoryAlignment = 16; - EXPECT_EQ(observed->Memory.Rva, - (expected->Memory.Rva + kMemoryAlignment - 1) & + EXPECT_EQ(observed_descriptor.Memory.Rva, + (expected_descriptor.Memory.Rva + kMemoryAlignment - 1) & ~(kMemoryAlignment - 1)); } } diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 6ca9bd40cb..82f8dd76fd 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -239,8 +239,6 @@ crashpad_static_library("snapshot") { public_configs = [ "..:crashpad_config" ] - configs = [ "..:disable_ubsan" ] - public_deps = [ ":context" ] deps = [ @@ -368,6 +366,8 @@ source_set("snapshot_test") { "linux/exception_snapshot_linux_test.cc", "linux/process_reader_linux_test.cc", "linux/system_snapshot_linux_test.cc", + "linux/test_modules.cc", + "linux/test_modules.h", "sanitized/process_snapshot_sanitized_test.cc", "sanitized/sanitization_information_test.cc", ] diff --git a/snapshot/linux/debug_rendezvous.h b/snapshot/linux/debug_rendezvous.h index 0c30e1ab92..90106c9d18 100644 --- a/snapshot/linux/debug_rendezvous.h +++ b/snapshot/linux/debug_rendezvous.h @@ -41,7 +41,7 @@ class DebugRendezvous { //! \brief The difference between the preferred load address in the ELF file //! and the actual loaded address in memory. - LinuxVMOffset load_bias; + VMAddress load_bias; //! \brief The address of the dynamic array for this object. LinuxVMAddress dynamic_array; diff --git a/snapshot/linux/debug_rendezvous_test.cc b/snapshot/linux/debug_rendezvous_test.cc index 45ba65025f..d32bd19370 100644 --- a/snapshot/linux/debug_rendezvous_test.cc +++ b/snapshot/linux/debug_rendezvous_test.cc @@ -27,6 +27,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/elf/elf_image_reader.h" +#include "snapshot/linux/test_modules.h" #include "test/linux/fake_ptrace_connection.h" #include "test/main_arguments.h" #include "test/multiprocess.h" @@ -34,6 +35,9 @@ #include "util/linux/auxiliary_vector.h" #include "util/linux/direct_ptrace_connection.h" #include "util/linux/memory_map.h" +#include "util/misc/address_sanitizer.h" +#include "util/misc/memory_sanitizer.h" +#include "util/numeric/safe_assignment.h" #include "util/process/process_memory_linux.h" #include "util/process/process_memory_range.h" @@ -45,6 +49,20 @@ namespace crashpad { namespace test { namespace { +void ExpectLoadBias(bool is_64_bit, + VMAddress unsigned_bias, + VMOffset signed_bias) { + if (is_64_bit) { + EXPECT_EQ(unsigned_bias, static_cast(signed_bias)); + } else { + uint32_t unsigned_bias32; + ASSERT_TRUE(AssignIfInRange(&unsigned_bias32, unsigned_bias)); + + uint32_t casted_bias32 = static_cast(signed_bias); + EXPECT_EQ(unsigned_bias32, casted_bias32); + } +} + void TestAgainstTarget(PtraceConnection* connection) { // Use ElfImageReader on the main executable which can tell us the debug // address. glibc declares the symbol _r_debug in link.h which we can use to @@ -112,9 +130,11 @@ void TestAgainstTarget(PtraceConnection* connection) { // Android's loader doesn't set the load bias until Android 4.3 (API 18). if (android_runtime_api >= 18) { - EXPECT_EQ(debug.Executable()->load_bias, exe_reader.GetLoadBias()); + ExpectLoadBias(connection->Is64Bit(), + debug.Executable()->load_bias, + exe_reader.GetLoadBias()); } else { - EXPECT_EQ(debug.Executable()->load_bias, 0); + EXPECT_EQ(debug.Executable()->load_bias, 0u); } for (const DebugRendezvous::LinkEntry& module : debug.Modules()) { @@ -130,7 +150,7 @@ void TestAgainstTarget(PtraceConnection* connection) { // (API 17). if (is_android_loader && android_runtime_api < 17) { EXPECT_EQ(module.dynamic_array, 0u); - EXPECT_EQ(module.load_bias, 0); + EXPECT_EQ(module.load_bias, 0u); continue; } @@ -170,7 +190,11 @@ void TestAgainstTarget(PtraceConnection* connection) { const std::string& module_name) { const bool is_vdso_mapping = device == 0 && inode == 0 && mapping_name == "[vdso]"; +#if defined(ARCH_CPU_X86) + static constexpr char kPrefix[] = "linux-gate.so."; +#else static constexpr char kPrefix[] = "linux-vdso.so."; +#endif return is_vdso_mapping == (module_name.empty() || module_name.compare(0, strlen(kPrefix), kPrefix) == 0); @@ -185,9 +209,11 @@ void TestAgainstTarget(PtraceConnection* connection) { // (API 20) until Android 6.0 (API 23). if (is_android_loader && android_runtime_api > 20 && android_runtime_api < 23) { - EXPECT_EQ(module.load_bias, 0); + EXPECT_EQ(module.load_bias, 0u); } else { - EXPECT_EQ(module.load_bias, module_reader->GetLoadBias()); + ExpectLoadBias(connection->Is64Bit(), + module.load_bias, + static_cast(module_reader->GetLoadBias())); } CheckedLinuxAddressRange module_range( @@ -197,6 +223,14 @@ void TestAgainstTarget(PtraceConnection* connection) { } TEST(DebugRendezvous, Self) { +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) + const std::string module_name = "test_module.so"; + const std::string module_soname = "test_module_soname"; + ScopedModuleHandle empty_test_module( + LoadTestModule(module_name, module_soname)); + ASSERT_TRUE(empty_test_module.valid()); +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER + FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(getpid())); diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index 98b99e6595..6373a3a01f 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -37,6 +37,7 @@ #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "snapshot/linux/test_modules.h" #include "test/errors.h" #include "test/linux/fake_ptrace_connection.h" #include "test/linux/get_tls.h" @@ -541,218 +542,7 @@ void ExpectModulesFromSelf( #endif // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 } -bool WriteTestModule(const base::FilePath& module_path, - const std::string& soname) { -#if defined(ARCH_CPU_64_BITS) - using Ehdr = Elf64_Ehdr; - using Phdr = Elf64_Phdr; - using Shdr = Elf64_Shdr; - using Dyn = Elf64_Dyn; - using Sym = Elf64_Sym; - unsigned char elf_class = ELFCLASS64; -#else - using Ehdr = Elf32_Ehdr; - using Phdr = Elf32_Phdr; - using Shdr = Elf32_Shdr; - using Dyn = Elf32_Dyn; - using Sym = Elf32_Sym; - unsigned char elf_class = ELFCLASS32; -#endif - - struct { - Ehdr ehdr; - struct { - Phdr load1; - Phdr load2; - Phdr dynamic; - } phdr_table; - struct { - Dyn hash; - Dyn strtab; - Dyn symtab; - Dyn strsz; - Dyn syment; - Dyn soname; - Dyn null; - } dynamic_array; - struct { - Elf32_Word nbucket; - Elf32_Word nchain; - Elf32_Word bucket; - Elf32_Word chain; - } hash_table; - char string_table[32]; - struct { - } section_header_string_table; - struct { - Sym und_symbol; - } symbol_table; - struct { - Shdr null; - Shdr dynamic; - Shdr string_table; - Shdr section_header_string_table; - } shdr_table; - } module = {}; - - module.ehdr.e_ident[EI_MAG0] = ELFMAG0; - module.ehdr.e_ident[EI_MAG1] = ELFMAG1; - module.ehdr.e_ident[EI_MAG2] = ELFMAG2; - module.ehdr.e_ident[EI_MAG3] = ELFMAG3; - - module.ehdr.e_ident[EI_CLASS] = elf_class; - -#if defined(ARCH_CPU_LITTLE_ENDIAN) - module.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; -#else - module.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; -#endif // ARCH_CPU_LITTLE_ENDIAN - - module.ehdr.e_ident[EI_VERSION] = EV_CURRENT; - - module.ehdr.e_type = ET_DYN; - -#if defined(ARCH_CPU_X86) - module.ehdr.e_machine = EM_386; -#elif defined(ARCH_CPU_X86_64) - module.ehdr.e_machine = EM_X86_64; -#elif defined(ARCH_CPU_ARMEL) - module.ehdr.e_machine = EM_ARM; -#elif defined(ARCH_CPU_ARM64) - module.ehdr.e_machine = EM_AARCH64; -#elif defined(ARCH_CPU_MIPSEL) || defined(ARCH_CPU_MIPS64EL) - module.ehdr.e_machine = EM_MIPS; -#endif - - module.ehdr.e_version = EV_CURRENT; - module.ehdr.e_ehsize = sizeof(module.ehdr); - - module.ehdr.e_phoff = offsetof(decltype(module), phdr_table); - module.ehdr.e_phnum = sizeof(module.phdr_table) / sizeof(Phdr); - module.ehdr.e_phentsize = sizeof(Phdr); - - module.ehdr.e_shoff = offsetof(decltype(module), shdr_table); - module.ehdr.e_shentsize = sizeof(Shdr); - module.ehdr.e_shnum = sizeof(module.shdr_table) / sizeof(Shdr); - module.ehdr.e_shstrndx = - offsetof(decltype(module.shdr_table), section_header_string_table) / - sizeof(Shdr); - - constexpr size_t load2_vaddr = 0x200000; - - module.phdr_table.load1.p_type = PT_LOAD; - module.phdr_table.load1.p_offset = 0; - module.phdr_table.load1.p_vaddr = 0; - module.phdr_table.load1.p_filesz = offsetof(decltype(module), shdr_table); - module.phdr_table.load1.p_memsz = offsetof(decltype(module), shdr_table); - module.phdr_table.load1.p_flags = PF_R; - module.phdr_table.load1.p_align = load2_vaddr; - - module.phdr_table.load2.p_type = PT_LOAD; - module.phdr_table.load2.p_offset = 0; - module.phdr_table.load2.p_vaddr = load2_vaddr; - module.phdr_table.load2.p_filesz = offsetof(decltype(module), shdr_table); - module.phdr_table.load2.p_memsz = offsetof(decltype(module), shdr_table); - module.phdr_table.load2.p_flags = PF_R | PF_W; - module.phdr_table.load2.p_align = load2_vaddr; - - module.phdr_table.dynamic.p_type = PT_DYNAMIC; - module.phdr_table.dynamic.p_offset = - offsetof(decltype(module), dynamic_array); - module.phdr_table.dynamic.p_vaddr = - load2_vaddr + module.phdr_table.dynamic.p_offset; - module.phdr_table.dynamic.p_filesz = sizeof(module.dynamic_array); - module.phdr_table.dynamic.p_memsz = sizeof(module.dynamic_array); - module.phdr_table.dynamic.p_flags = PF_R | PF_W; - module.phdr_table.dynamic.p_align = 8; - - module.dynamic_array.hash.d_tag = DT_HASH; - module.dynamic_array.hash.d_un.d_ptr = offsetof(decltype(module), hash_table); - module.dynamic_array.strtab.d_tag = DT_STRTAB; - module.dynamic_array.strtab.d_un.d_ptr = - offsetof(decltype(module), string_table); - module.dynamic_array.symtab.d_tag = DT_SYMTAB; - module.dynamic_array.symtab.d_un.d_ptr = - offsetof(decltype(module), symbol_table); - module.dynamic_array.strsz.d_tag = DT_STRSZ; - module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table); - module.dynamic_array.syment.d_tag = DT_SYMENT; - module.dynamic_array.syment.d_un.d_val = sizeof(Sym); - constexpr size_t kSonameOffset = 1; - module.dynamic_array.soname.d_tag = DT_SONAME; - module.dynamic_array.soname.d_un.d_val = kSonameOffset; - - module.dynamic_array.null.d_tag = DT_NULL; - - module.hash_table.nbucket = 1; - module.hash_table.nchain = 1; - module.hash_table.bucket = 0; - module.hash_table.chain = 0; - - CHECK_GE(sizeof(module.string_table), soname.size() + 2); - module.string_table[0] = '\0'; - memcpy(&module.string_table[kSonameOffset], soname.c_str(), soname.size()); - - module.shdr_table.null.sh_type = SHT_NULL; - - module.shdr_table.dynamic.sh_name = 0; - module.shdr_table.dynamic.sh_type = SHT_DYNAMIC; - module.shdr_table.dynamic.sh_flags = SHF_WRITE | SHF_ALLOC; - module.shdr_table.dynamic.sh_addr = module.phdr_table.dynamic.p_vaddr; - module.shdr_table.dynamic.sh_offset = module.phdr_table.dynamic.p_offset; - module.shdr_table.dynamic.sh_size = module.phdr_table.dynamic.p_filesz; - module.shdr_table.dynamic.sh_link = - offsetof(decltype(module.shdr_table), string_table) / sizeof(Shdr); - - module.shdr_table.string_table.sh_name = 0; - module.shdr_table.string_table.sh_type = SHT_STRTAB; - module.shdr_table.string_table.sh_offset = - offsetof(decltype(module), string_table); - module.shdr_table.string_table.sh_size = sizeof(module.string_table); - - module.shdr_table.section_header_string_table.sh_name = 0; - module.shdr_table.section_header_string_table.sh_type = SHT_STRTAB; - module.shdr_table.section_header_string_table.sh_offset = - offsetof(decltype(module), section_header_string_table); - module.shdr_table.section_header_string_table.sh_size = - sizeof(module.section_header_string_table); - - FileWriter writer; - if (!writer.Open(module_path, - FileWriteMode::kCreateOrFail, - FilePermissions::kWorldReadable)) { - ADD_FAILURE(); - return false; - } - - if (!writer.Write(&module, sizeof(module))) { - ADD_FAILURE(); - return false; - } - - return true; -} - -ScopedModuleHandle LoadTestModule(const std::string& module_name, - const std::string& module_soname) { - base::FilePath module_path( - TestPaths::Executable().DirName().Append(module_name)); - - if (!WriteTestModule(module_path, module_soname)) { - return ScopedModuleHandle(nullptr); - } - EXPECT_TRUE(IsRegularFile(module_path)); - - ScopedModuleHandle handle( - dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL)); - EXPECT_TRUE(handle.valid()) - << "dlopen: " << module_path.value() << " " << dlerror(); - - EXPECT_TRUE(LoggingRemoveFile(module_path)); - - return handle; -} - +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) void ExpectTestModule(ProcessReaderLinux* reader, const std::string& module_name) { for (const auto& module : reader->Modules()) { @@ -771,13 +561,16 @@ void ExpectTestModule(ProcessReaderLinux* reader, } ADD_FAILURE() << "Test module not found"; } +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER TEST(ProcessReaderLinux, SelfModules) { +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) const std::string module_name = "test_module.so"; const std::string module_soname = "test_module_soname"; ScopedModuleHandle empty_test_module( LoadTestModule(module_name, module_soname)); ASSERT_TRUE(empty_test_module.valid()); +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER FakePtraceConnection connection; connection.Initialize(getpid()); @@ -786,7 +579,9 @@ TEST(ProcessReaderLinux, SelfModules) { ASSERT_TRUE(process_reader.Initialize(&connection)); ExpectModulesFromSelf(process_reader.Modules()); +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) ExpectTestModule(&process_reader, module_soname); +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER } class ChildModuleTest : public Multiprocess { @@ -806,13 +601,17 @@ class ChildModuleTest : public Multiprocess { ASSERT_TRUE(process_reader.Initialize(&connection)); ExpectModulesFromSelf(process_reader.Modules()); +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) ExpectTestModule(&process_reader, module_soname_); +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER } void MultiprocessChild() override { +#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) ScopedModuleHandle empty_test_module( LoadTestModule("test_module.so", module_soname_)); ASSERT_TRUE(empty_test_module.valid()); +#endif // !ADDRESS_SANITIZER && !MEMORY_SANITIZER char c = 0; ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &c, sizeof(c))); diff --git a/snapshot/linux/test_modules.cc b/snapshot/linux/test_modules.cc new file mode 100644 index 0000000000..b2450c2067 --- /dev/null +++ b/snapshot/linux/test_modules.cc @@ -0,0 +1,262 @@ +// Copyright 2020 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "snapshot/linux/test_modules.h" + +#include + +#include + +#include "base/check_op.h" +#include "base/files/file_path.h" +#include "build/build_config.h" +#include "gtest/gtest.h" +#include "test/test_paths.h" +#include "util/file/filesystem.h" +#include "util/file/file_writer.h" + +namespace crashpad { +namespace test { + +bool WriteTestModule(const base::FilePath& module_path, + const std::string& soname) { +#if defined(ARCH_CPU_64_BITS) + using Ehdr = Elf64_Ehdr; + using Phdr = Elf64_Phdr; + using Shdr = Elf64_Shdr; + using Dyn = Elf64_Dyn; + using Sym = Elf64_Sym; + unsigned char elf_class = ELFCLASS64; +#else + using Ehdr = Elf32_Ehdr; + using Phdr = Elf32_Phdr; + using Shdr = Elf32_Shdr; + using Dyn = Elf32_Dyn; + using Sym = Elf32_Sym; + unsigned char elf_class = ELFCLASS32; +#endif + + struct { + Ehdr ehdr; + struct { + Phdr load1; + Phdr load2; + Phdr dynamic; + } phdr_table; + struct { + Dyn hash; + Dyn strtab; + Dyn symtab; + Dyn strsz; + Dyn syment; + Dyn soname; + Dyn null; + } dynamic_array; + struct { + Elf32_Word nbucket; + Elf32_Word nchain; + Elf32_Word bucket; + Elf32_Word chain; + } hash_table; + char string_table[32]; + struct { + } section_header_string_table; + struct { + Sym und_symbol; + } symbol_table; + struct { + Shdr null; + Shdr dynamic; + Shdr string_table; + Shdr section_header_string_table; + } shdr_table; + } module = {}; + + module.ehdr.e_ident[EI_MAG0] = ELFMAG0; + module.ehdr.e_ident[EI_MAG1] = ELFMAG1; + module.ehdr.e_ident[EI_MAG2] = ELFMAG2; + module.ehdr.e_ident[EI_MAG3] = ELFMAG3; + + module.ehdr.e_ident[EI_CLASS] = elf_class; + +#if defined(ARCH_CPU_LITTLE_ENDIAN) + module.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; +#else + module.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; +#endif // ARCH_CPU_LITTLE_ENDIAN + + module.ehdr.e_ident[EI_VERSION] = EV_CURRENT; + + module.ehdr.e_type = ET_DYN; + +#if defined(ARCH_CPU_X86) + module.ehdr.e_machine = EM_386; +#elif defined(ARCH_CPU_X86_64) + module.ehdr.e_machine = EM_X86_64; +#elif defined(ARCH_CPU_ARMEL) + module.ehdr.e_machine = EM_ARM; +#elif defined(ARCH_CPU_ARM64) + module.ehdr.e_machine = EM_AARCH64; +#elif defined(ARCH_CPU_MIPSEL) || defined(ARCH_CPU_MIPS64EL) + module.ehdr.e_machine = EM_MIPS; +#endif + + module.ehdr.e_version = EV_CURRENT; + module.ehdr.e_ehsize = sizeof(module.ehdr); + + module.ehdr.e_phoff = offsetof(decltype(module), phdr_table); + module.ehdr.e_phnum = sizeof(module.phdr_table) / sizeof(Phdr); + module.ehdr.e_phentsize = sizeof(Phdr); + + module.ehdr.e_shoff = offsetof(decltype(module), shdr_table); + module.ehdr.e_shentsize = sizeof(Shdr); + module.ehdr.e_shnum = sizeof(module.shdr_table) / sizeof(Shdr); + module.ehdr.e_shstrndx = + offsetof(decltype(module.shdr_table), section_header_string_table) / + sizeof(Shdr); + + const size_t page_size = getpagesize(); + auto align = [page_size](uintptr_t addr) { + return (addr + page_size - 1) & ~(page_size - 1); + }; + constexpr size_t segment_size = offsetof(decltype(module), shdr_table); + + // This test module covers cases where: + // 1. Multiple segments are mapped from file offset 0. + // 2. Load bias is negative. + + const uintptr_t load2_vaddr = align(std::numeric_limits::max() - + align(segment_size) - page_size); + const uintptr_t load1_vaddr = load2_vaddr - align(segment_size); + + module.phdr_table.load1.p_type = PT_LOAD; + module.phdr_table.load1.p_offset = 0; + module.phdr_table.load1.p_vaddr = load1_vaddr; + module.phdr_table.load1.p_filesz = segment_size; + module.phdr_table.load1.p_memsz = segment_size; + module.phdr_table.load1.p_flags = PF_R; + module.phdr_table.load1.p_align = page_size; + + module.phdr_table.load2.p_type = PT_LOAD; + module.phdr_table.load2.p_offset = 0; + module.phdr_table.load2.p_vaddr = load2_vaddr; + module.phdr_table.load2.p_filesz = segment_size; + module.phdr_table.load2.p_memsz = segment_size; + module.phdr_table.load2.p_flags = PF_R | PF_W; + module.phdr_table.load2.p_align = page_size; + + module.phdr_table.dynamic.p_type = PT_DYNAMIC; + module.phdr_table.dynamic.p_offset = + offsetof(decltype(module), dynamic_array); + module.phdr_table.dynamic.p_vaddr = + load2_vaddr + module.phdr_table.dynamic.p_offset; + module.phdr_table.dynamic.p_filesz = sizeof(module.dynamic_array); + module.phdr_table.dynamic.p_memsz = sizeof(module.dynamic_array); + module.phdr_table.dynamic.p_flags = PF_R | PF_W; + module.phdr_table.dynamic.p_align = 8; + + module.dynamic_array.hash.d_tag = DT_HASH; + module.dynamic_array.hash.d_un.d_ptr = + load1_vaddr + offsetof(decltype(module), hash_table); + module.dynamic_array.strtab.d_tag = DT_STRTAB; + module.dynamic_array.strtab.d_un.d_ptr = + load1_vaddr + offsetof(decltype(module), string_table); + module.dynamic_array.symtab.d_tag = DT_SYMTAB; + module.dynamic_array.symtab.d_un.d_ptr = + load1_vaddr + offsetof(decltype(module), symbol_table); + module.dynamic_array.strsz.d_tag = DT_STRSZ; + module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table); + module.dynamic_array.syment.d_tag = DT_SYMENT; + module.dynamic_array.syment.d_un.d_val = sizeof(Sym); + constexpr size_t kSonameOffset = 1; + module.dynamic_array.soname.d_tag = DT_SONAME; + module.dynamic_array.soname.d_un.d_val = kSonameOffset; + + module.dynamic_array.null.d_tag = DT_NULL; + + module.hash_table.nbucket = 1; + module.hash_table.nchain = 1; + module.hash_table.bucket = 0; + module.hash_table.chain = 0; + + if (sizeof(module.string_table) < soname.size() + 2) { + ADD_FAILURE() << "string table too small"; + return false; + } + module.string_table[0] = '\0'; + memcpy(&module.string_table[kSonameOffset], soname.c_str(), soname.size()); + + module.shdr_table.null.sh_type = SHT_NULL; + + module.shdr_table.dynamic.sh_name = 0; + module.shdr_table.dynamic.sh_type = SHT_DYNAMIC; + module.shdr_table.dynamic.sh_flags = SHF_WRITE | SHF_ALLOC; + module.shdr_table.dynamic.sh_addr = module.phdr_table.dynamic.p_vaddr; + module.shdr_table.dynamic.sh_offset = module.phdr_table.dynamic.p_offset; + module.shdr_table.dynamic.sh_size = module.phdr_table.dynamic.p_filesz; + module.shdr_table.dynamic.sh_link = + offsetof(decltype(module.shdr_table), string_table) / sizeof(Shdr); + + module.shdr_table.string_table.sh_name = 0; + module.shdr_table.string_table.sh_type = SHT_STRTAB; + module.shdr_table.string_table.sh_offset = + offsetof(decltype(module), string_table); + module.shdr_table.string_table.sh_size = sizeof(module.string_table); + + module.shdr_table.section_header_string_table.sh_name = 0; + module.shdr_table.section_header_string_table.sh_type = SHT_STRTAB; + module.shdr_table.section_header_string_table.sh_offset = + offsetof(decltype(module), section_header_string_table); + module.shdr_table.section_header_string_table.sh_size = + sizeof(module.section_header_string_table); + + FileWriter writer; + if (!writer.Open(module_path, + FileWriteMode::kCreateOrFail, + FilePermissions::kWorldReadable)) { + ADD_FAILURE(); + return false; + } + + if (!writer.Write(&module, sizeof(module))) { + ADD_FAILURE(); + LoggingRemoveFile(module_path); + return false; + } + + return true; +} + +ScopedModuleHandle LoadTestModule(const std::string& module_name, + const std::string& module_soname) { + base::FilePath module_path( + TestPaths::Executable().DirName().Append(module_name)); + + if (!WriteTestModule(module_path, module_soname)) { + return ScopedModuleHandle(nullptr); + } + EXPECT_TRUE(IsRegularFile(module_path)); + + ScopedModuleHandle handle( + dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL)); + EXPECT_TRUE(handle.valid()) + << "dlopen: " << module_path.value() << " " << dlerror(); + + EXPECT_TRUE(LoggingRemoveFile(module_path)); + + return handle; +} + +} // namespace test +} // namespace crashpad diff --git a/snapshot/linux/test_modules.h b/snapshot/linux/test_modules.h new file mode 100644 index 0000000000..b791480a1d --- /dev/null +++ b/snapshot/linux/test_modules.h @@ -0,0 +1,37 @@ +// Copyright 2020 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_SNAPSHOT_LINUX_TEST_MODULES_H_ +#define CRASHPAD_SNAPSHOT_LINUX_TEST_MODULES_H_ + +#include + +#include "test/scoped_module_handle.h" + +namespace crashpad { +namespace test { + +//! \brief Constructs and loads a test module. +//! +//! \param module_name The filename of the mdoule. +//! \param module_soname The SONAME for the module. +//! \return a handle to the loaded module on success. On failure, the handle +//! will be invalid and a message will be logged. +ScopedModuleHandle LoadTestModule(const std::string& module_name, + const std::string& module_soname); + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index c42e7ccfa0..4f85b77cfd 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -318,7 +318,7 @@ bool ProcessSnapshotMinidump::InitializeMiscInfo() { #else full_version_ = base::UTF16ToUTF8(info.BuildString); #endif - full_version_ = full_version_.substr(0, full_version_.find(";")); + full_version_ = full_version_.substr(0, full_version_.find(';')); FALLTHROUGH; case sizeof(MINIDUMP_MISC_INFO_3): case sizeof(MINIDUMP_MISC_INFO_2): diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index 43de7254a3..a4d4d9e00f 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -80,6 +80,8 @@ 'linux/exception_snapshot_linux_test.cc', 'linux/process_reader_linux_test.cc', 'linux/system_snapshot_linux_test.cc', + 'linux/test_modules.cc', + 'linux/test_modules.h', 'mac/cpu_context_mac_test.cc', 'mac/mach_o_image_annotations_reader_test.cc', 'mac/mach_o_image_reader_test.cc', diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx index b25208d88b..87004b2901 100644 --- a/test/fuchsia_crashpad_tests.cmx +++ b/test/fuchsia_crashpad_tests.cmx @@ -7,6 +7,9 @@ } } }, + "include": [ + "sdk/lib/diagnostics/syslog/client.shard.cmx" + ], "program": { "binary": "test/crashpad_tests" }, diff --git a/third_party/edo/BUILD.gn b/third_party/edo/BUILD.gn index 2b8d5b994f..73dca1aab4 100644 --- a/third_party/edo/BUILD.gn +++ b/third_party/edo/BUILD.gn @@ -124,8 +124,8 @@ if (crashpad_is_in_chromium) { "edo/Service/Sources/NSKeyedArchiver+EDOAdditions.m", "edo/Service/Sources/NSKeyedUnarchiver+EDOAdditions.h", "edo/Service/Sources/NSKeyedUnarchiver+EDOAdditions.m", - "edo/Service/Sources/NSObject+EDOBlacklistedType.h", - "edo/Service/Sources/NSObject+EDOBlacklistedType.m", + "edo/Service/Sources/NSObject+EDOBlockedType.h", + "edo/Service/Sources/NSObject+EDOBlockedType.m", "edo/Service/Sources/NSObject+EDOParameter.h", "edo/Service/Sources/NSObject+EDOParameter.m", "edo/Service/Sources/NSObject+EDOValue.h", diff --git a/third_party/googletest/BUILD.gn b/third_party/googletest/BUILD.gn index 4ad44a43e3..f51db0e9d5 100644 --- a/third_party/googletest/BUILD.gn +++ b/third_party/googletest/BUILD.gn @@ -28,7 +28,6 @@ if (crashpad_is_in_chromium) { group("googletest") { testonly = true public_deps = [ "//third_party/googletest:gtest" ] - public_configs = [ "../..:disable_ubsan" ] } group("googlemock") { testonly = true diff --git a/third_party/lss/README.crashpad b/third_party/lss/README.crashpad index c036ae0f22..d1ac9913ed 100644 --- a/third_party/lss/README.crashpad +++ b/third_party/lss/README.crashpad @@ -3,7 +3,7 @@ Short Name: lss URL: https://chromium.googlesource.com/linux-syscall-support/ Revision: See DEPS License: BSD 3-clause -License File: lss/linux-syscall-support.h +License File: lss/linux_syscall_support.h Security Critical: yes Description: diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index cb82d71291..c748b289b8 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit cb82d71291f19590d3ee138ba64fcf1e9e0edd84 +Subproject commit c748b289b825056985f3dd3b36dc86c766d787ad diff --git a/util/BUILD.gn b/util/BUILD.gn index ab0d3294be..adedf9545b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -77,6 +77,7 @@ if (crashpad_is_mac || crashpad_is_ios) { migcom_path, ] } + deps = [ "//build/config/mac:sdk_inputs" ] } if (sysroot != "") { if (crashpad_is_in_chromium) { @@ -564,8 +565,6 @@ crashpad_static_library("util") { public_configs = [ "..:crashpad_config" ] - configs = [ "..:disable_ubsan" ] - # Include generated files starting with "util". if (crashpad_is_in_fuchsia) { include_dirs = [ "$root_gen_dir/third_party/crashpad" ] diff --git a/util/file/file_io.cc b/util/file/file_io.cc index c1da67226e..3bd86cc465 100644 --- a/util/file/file_io.cc +++ b/util/file/file_io.cc @@ -66,11 +66,12 @@ class FileIOWriteAll final : public internal::WriteAllInternal { namespace internal { bool ReadExactlyInternal::ReadExactly(void* buffer, size_t size, bool can_log) { - char* buffer_c = static_cast(buffer); + uintptr_t buffer_int = reinterpret_cast(buffer); size_t total_bytes = 0; size_t remaining = size; while (remaining > 0) { - FileOperationResult bytes_read = Read(buffer_c, remaining, can_log); + FileOperationResult bytes_read = + Read(reinterpret_cast(buffer_int), remaining, can_log); if (bytes_read < 0) { return false; } @@ -81,7 +82,7 @@ bool ReadExactlyInternal::ReadExactly(void* buffer, size_t size, bool can_log) { break; } - buffer_c += bytes_read; + buffer_int += bytes_read; remaining -= bytes_read; total_bytes += bytes_read; } @@ -96,17 +97,18 @@ bool ReadExactlyInternal::ReadExactly(void* buffer, size_t size, bool can_log) { } bool WriteAllInternal::WriteAll(const void* buffer, size_t size) { - const char* buffer_c = static_cast(buffer); + uintptr_t buffer_int = reinterpret_cast(buffer); while (size > 0) { - FileOperationResult bytes_written = Write(buffer_c, size); + FileOperationResult bytes_written = + Write(reinterpret_cast(buffer_int), size); if (bytes_written < 0) { return false; } DCHECK_NE(bytes_written, 0); - buffer_c += bytes_written; + buffer_int += bytes_written; size -= bytes_written; } diff --git a/util/linux/initial_signal_dispositions.cc b/util/linux/initial_signal_dispositions.cc index b72b2476ed..9d980a11fb 100644 --- a/util/linux/initial_signal_dispositions.cc +++ b/util/linux/initial_signal_dispositions.cc @@ -20,9 +20,10 @@ #include "base/logging.h" #include "build/build_config.h" +namespace crashpad { + #if __ANDROID_API__ <= 23 -namespace crashpad { namespace { bool LoggingSignal(int signum, sighandler_t handler) { sighandler_t previous = signal(signum, handler); diff --git a/util/linux/ptrace_broker.cc b/util/linux/ptrace_broker.cc index b6b5bb131d..68621f2cc5 100644 --- a/util/linux/ptrace_broker.cc +++ b/util/linux/ptrace_broker.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,11 @@ #include "base/check_op.h" #include "base/posix/eintr_wrapper.h" +#include "base/process/process_metrics.h" +#include "third_party/lss/lss.h" +#include "util/linux/scoped_ptrace_attach.h" #include "util/misc/memory_sanitizer.h" +#include "util/posix/scoped_mmap.h" namespace crashpad { @@ -52,18 +57,58 @@ size_t FormatPID(char* buffer, pid_t pid) { } // namespace +class PtraceBroker::AttachmentsArray { + public: + AttachmentsArray() : allocation_(false), attach_count_(0) {} + + ~AttachmentsArray() { + for (size_t index = 0; index < attach_count_; ++index) { + PtraceDetach(Attachments()[index], false); + } + } + + bool Initialize() { + return allocation_.ResetMmap(nullptr, + base::GetPageSize(), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); + } + + bool Attach(pid_t pid) { + pid_t* attach = AllocateAttachment(); + if (!attach || !PtraceAttach(pid, false)) { + return false; + } + + *attach = pid; + return true; + } + + private: + pid_t* AllocateAttachment() { + if (attach_count_ >= (allocation_.len() / sizeof(pid_t))) { + return nullptr; + } + return &Attachments()[attach_count_++]; + } + + pid_t* Attachments() { return allocation_.addr_as(); } + + ScopedMmap allocation_; + size_t attach_count_; + + DISALLOW_COPY_AND_ASSIGN(AttachmentsArray); +}; + PtraceBroker::PtraceBroker(int sock, pid_t pid, bool is_64_bit) : ptracer_(is_64_bit, /* can_log= */ false), file_root_(file_root_buffer_), - attachments_(nullptr), - attach_count_(0), - attach_capacity_(0), memory_file_(), sock_(sock), memory_pid_(pid), tried_opening_mem_file_(false) { - AllocateAttachments(); - static constexpr char kProc[] = "/proc/"; size_t root_length = strlen(kProc); memcpy(file_root_buffer_, kProc, root_length); @@ -88,35 +133,12 @@ void PtraceBroker::SetFileRoot(const char* new_root) { } int PtraceBroker::Run() { - int result = RunImpl(); - ReleaseAttachments(); - return result; -} - -bool PtraceBroker::AllocateAttachments() { - constexpr size_t page_size = 4096; - constexpr size_t alloc_size = - (sizeof(ScopedPtraceAttach) + page_size - 1) & ~(page_size - 1); - void* alloc = sbrk(alloc_size); - if (reinterpret_cast(alloc) == -1) { - return false; - } - - if (attachments_ == nullptr) { - attachments_ = reinterpret_cast(alloc); - } - - attach_capacity_ += alloc_size / sizeof(ScopedPtraceAttach); - return true; + AttachmentsArray attachments; + attachments.Initialize(); + return RunImpl(&attachments); } -void PtraceBroker::ReleaseAttachments() { - for (size_t index = 0; index < attach_count_; ++index) { - attachments_[index].Reset(); - } -} - -int PtraceBroker::RunImpl() { +int PtraceBroker::RunImpl(AttachmentsArray* attachments) { while (true) { Request request = {}; if (!ReadFileExactly(sock_, &request, sizeof(request))) { @@ -129,25 +151,10 @@ int PtraceBroker::RunImpl() { switch (request.type) { case Request::kTypeAttach: { - ScopedPtraceAttach* attach; - ScopedPtraceAttach stack_attach; - bool attach_on_stack = false; - - if (attach_capacity_ > attach_count_ || AllocateAttachments()) { - attach = new (&attachments_[attach_count_]) ScopedPtraceAttach; - } else { - attach = &stack_attach; - attach_on_stack = true; - } - ExceptionHandlerProtocol::Bool status = - ExceptionHandlerProtocol::kBoolFalse; - if (attach->ResetAttach(request.tid)) { - status = ExceptionHandlerProtocol::kBoolTrue; - if (!attach_on_stack) { - ++attach_count_; - } - } + attachments->Attach(request.tid) + ? ExceptionHandlerProtocol::kBoolTrue + : ExceptionHandlerProtocol::kBoolFalse; if (!WriteFile(sock_, &status, sizeof(status))) { return errno; @@ -160,9 +167,6 @@ int PtraceBroker::RunImpl() { } } - if (attach_on_stack && status == ExceptionHandlerProtocol::kBoolTrue) { - return RunImpl(); - } continue; } diff --git a/util/linux/ptrace_broker.h b/util/linux/ptrace_broker.h index 6a7bfb723d..5d90cb2027 100644 --- a/util/linux/ptrace_broker.h +++ b/util/linux/ptrace_broker.h @@ -24,7 +24,6 @@ #include "util/linux/exception_handler_protocol.h" #include "util/linux/ptrace_connection.h" #include "util/linux/ptracer.h" -#include "util/linux/scoped_ptrace_attach.h" #include "util/linux/thread_info.h" #include "util/misc/address_types.h" @@ -186,16 +185,13 @@ class PtraceBroker { //! This method returns when a PtraceBrokerRequest with type kTypeExit is //! received or an error is encountered on the socket. //! - //! This method calls `sbrk`, which may break other memory management tools, - //! such as `malloc`. - //! //! \return 0 if Run() exited due to an exit request. Otherwise an error code. int Run(); private: - bool AllocateAttachments(); - void ReleaseAttachments(); - int RunImpl(); + class AttachmentsArray; + + int RunImpl(AttachmentsArray*); int SendError(ExceptionHandlerProtocol::Errno err); int SendReadError(ReadError err); int SendOpenResult(OpenResult result); @@ -210,9 +206,6 @@ class PtraceBroker { char file_root_buffer_[32]; Ptracer ptracer_; const char* file_root_; - ScopedPtraceAttach* attachments_; - size_t attach_count_; - size_t attach_capacity_; ScopedFileHandle memory_file_; int sock_; pid_t memory_pid_; diff --git a/util/linux/scoped_ptrace_attach.cc b/util/linux/scoped_ptrace_attach.cc index 09e3fba56c..eed8345563 100644 --- a/util/linux/scoped_ptrace_attach.cc +++ b/util/linux/scoped_ptrace_attach.cc @@ -22,6 +22,32 @@ namespace crashpad { +bool PtraceAttach(pid_t pid, bool can_log) { + if (ptrace(PTRACE_ATTACH, pid, nullptr, nullptr) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + + int status; + if (HANDLE_EINTR(waitpid(pid, &status, __WALL)) < 0) { + PLOG_IF(ERROR, can_log) << "waitpid"; + return false; + } + if (!WIFSTOPPED(status)) { + LOG_IF(ERROR, can_log) << "process not stopped"; + return false; + } + return true; +} + +bool PtraceDetach(pid_t pid, bool can_log) { + if (pid >= 0 && ptrace(PTRACE_DETACH, pid, nullptr, nullptr) != 0) { + PLOG_IF(ERROR, can_log) << "ptrace"; + return false; + } + return true; +} + ScopedPtraceAttach::ScopedPtraceAttach() : pid_(-1) {} @@ -30,8 +56,7 @@ ScopedPtraceAttach::~ScopedPtraceAttach() { } bool ScopedPtraceAttach::Reset() { - if (pid_ >= 0 && ptrace(PTRACE_DETACH, pid_, nullptr, nullptr) != 0) { - PLOG(ERROR) << "ptrace"; + if (!PtraceDetach(pid_, true)) { return false; } pid_ = -1; @@ -41,21 +66,11 @@ bool ScopedPtraceAttach::Reset() { bool ScopedPtraceAttach::ResetAttach(pid_t pid) { Reset(); - if (ptrace(PTRACE_ATTACH, pid, nullptr, nullptr) != 0) { - PLOG(ERROR) << "ptrace"; + if (!PtraceAttach(pid, true)) { return false; } - pid_ = pid; - int status; - if (HANDLE_EINTR(waitpid(pid_, &status, __WALL)) < 0) { - PLOG(ERROR) << "waitpid"; - return false; - } - if (!WIFSTOPPED(status)) { - LOG(ERROR) << "process not stopped"; - return false; - } + pid_ = pid; return true; } diff --git a/util/linux/scoped_ptrace_attach.h b/util/linux/scoped_ptrace_attach.h index a3d9d6987f..f380d254db 100644 --- a/util/linux/scoped_ptrace_attach.h +++ b/util/linux/scoped_ptrace_attach.h @@ -21,6 +21,24 @@ namespace crashpad { +//! \brief Attaches to the process with process ID \a pid and blocks until the +//! target process has stopped by calling `waitpid()`. +//! +//! \param pid The process ID of the process to attach to. +//! \param can_log Whether this function may log messages on failure. +//! \return `true` on success. `false` on failure with a message logged if \a +//! can_log is `true`. +bool PtraceAttach(pid_t pid, bool can_log = true); + +//! \brief Detaches the process with process ID \a pid. The process must +//! already be ptrace attached. +//! +//! \param pid The process ID of the process to detach. +//! \param can_log Whether this function may log messages on failure. +//! \return `true` on success. `false` on failure with a message logged if \a +//! ca_log is `true `true` +bool PtraceDetach(pid_t pid, bool can_log = true); + //! \brief Maintains a `ptrace()` attachment to a process. //! //! On destruction, the process will be detached. diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index ce548f3304..1d5ca878b1 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -419,7 +419,7 @@ bool WriteRequest(Stream* stream, } } - write_start = buf.crlf - size_len; + write_start = static_cast(buf.crlf) - size_len; write_size = size_len + sizeof(buf.crlf) + data_bytes + kCRLFSize; } else { // When not using chunked encoding, only use buf.data. diff --git a/util/posix/scoped_mmap.cc b/util/posix/scoped_mmap.cc index 0c98ba24a2..21533d2374 100644 --- a/util/posix/scoped_mmap.cc +++ b/util/posix/scoped_mmap.cc @@ -22,12 +22,54 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" +#include "base/process/process_metrics.h" +#include "build/build_config.h" + +#if defined(OS_LINUX) +#include "third_party/lss/lss.h" +#endif namespace { -bool Munmap(uintptr_t addr, size_t len) { - if (munmap(reinterpret_cast(addr), len) != 0) { - PLOG(ERROR) << "munmap"; +#if defined(OS_LINUX) +void* CallMmap(void* addr, + size_t len, + int prot, + int flags, + int fd, + off_t offset) { + return sys_mmap(addr, len, prot, flags, fd, offset); +} + +int CallMunmap(void* addr, size_t len) { + return sys_munmap(addr, len); +} + +int CallMprotect(void* addr, size_t len, int prot) { + return sys_mprotect(addr, len, prot); +} +#else +void* CallMmap(void* addr, + size_t len, + int prot, + int flags, + int fd, + off_t offset) { + return mmap(addr, len, prot, flags, fd, offset); +} + +int CallMunmap(void* addr, size_t len) { + return munmap(addr, len); +} + +int CallMprotect(void* addr, size_t len, int prot) { + return mprotect(addr, len, prot); +} +#endif + +bool LoggingMunmap(uintptr_t addr, size_t len, bool can_log) { + if (CallMunmap(reinterpret_cast(addr), len) != 0) { + PLOG_IF(ERROR, can_log) << "munmap"; return false; } @@ -35,7 +77,7 @@ bool Munmap(uintptr_t addr, size_t len) { } size_t RoundPage(size_t size) { - const size_t kPageMask = base::checked_cast(getpagesize()) - 1; + const size_t kPageMask = base::checked_cast(base::GetPageSize()) - 1; return (size + kPageMask) & ~kPageMask; } @@ -43,11 +85,12 @@ size_t RoundPage(size_t size) { namespace crashpad { -ScopedMmap::ScopedMmap() {} +ScopedMmap::ScopedMmap(bool can_log) : can_log_(can_log) {} ScopedMmap::~ScopedMmap() { if (is_valid()) { - Munmap(reinterpret_cast(addr_), RoundPage(len_)); + LoggingMunmap( + reinterpret_cast(addr_), RoundPage(len_), can_log_); } } @@ -63,7 +106,7 @@ bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { DCHECK_EQ(len, 0u); } else { DCHECK_NE(len, 0u); - DCHECK_EQ(new_addr % getpagesize(), 0u); + DCHECK_EQ(new_addr % base::GetPageSize(), 0u); DCHECK((base::CheckedNumeric(new_addr) + (new_len_round - 1)) .IsValid()); } @@ -74,11 +117,13 @@ bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { const uintptr_t old_addr = reinterpret_cast(addr_); const size_t old_len_round = RoundPage(len_); if (old_addr < new_addr) { - result &= Munmap(old_addr, std::min(old_len_round, new_addr - old_addr)); + result &= LoggingMunmap( + old_addr, std::min(old_len_round, new_addr - old_addr), can_log_); } if (old_addr + old_len_round > new_addr + new_len_round) { uintptr_t unmap_start = std::max(old_addr, new_addr + new_len_round); - result &= Munmap(unmap_start, old_addr + old_len_round - unmap_start); + result &= LoggingMunmap( + unmap_start, old_addr + old_len_round - unmap_start, can_log_); } } @@ -100,9 +145,9 @@ bool ScopedMmap::ResetMmap(void* addr, // consider the return value from Reset(). Reset(); - void* new_addr = mmap(addr, len, prot, flags, fd, offset); + void* new_addr = CallMmap(addr, len, prot, flags, fd, offset); if (new_addr == MAP_FAILED) { - PLOG(ERROR) << "mmap"; + PLOG_IF(ERROR, can_log_) << "mmap"; return false; } @@ -113,8 +158,8 @@ bool ScopedMmap::ResetMmap(void* addr, } bool ScopedMmap::Mprotect(int prot) { - if (mprotect(addr_, RoundPage(len_), prot) < 0) { - PLOG(ERROR) << "mprotect"; + if (CallMprotect(addr_, RoundPage(len_), prot) < 0) { + PLOG_IF(ERROR, can_log_) << "mprotect"; return false; } diff --git a/util/posix/scoped_mmap.h b/util/posix/scoped_mmap.h index b497d944ff..12f5ceed71 100644 --- a/util/posix/scoped_mmap.h +++ b/util/posix/scoped_mmap.h @@ -30,7 +30,10 @@ namespace crashpad { //! will be released by calling `munmap()`. class ScopedMmap { public: - ScopedMmap(); + //! \brief Constructs this object. + //! + //! \param can_log `true` if methods of this class may log messages. + explicit ScopedMmap(bool can_log = true); ~ScopedMmap(); //! \brief Releases the memory-mapped region by calling `munmap()`. @@ -105,6 +108,7 @@ class ScopedMmap { private: void* addr_ = MAP_FAILED; size_t len_ = 0; + bool can_log_; DISALLOW_COPY_AND_ASSIGN(ScopedMmap); }; diff --git a/util/stdlib/aligned_allocator.h b/util/stdlib/aligned_allocator.h index 97be27a271..4e64744e69 100644 --- a/util/stdlib/aligned_allocator.h +++ b/util/stdlib/aligned_allocator.h @@ -69,7 +69,7 @@ struct AlignedAllocator { pointer address(reference x) const noexcept { return &x; } const_pointer address(const_reference x) const noexcept { return &x; } - pointer allocate(size_type n, std::allocator::const_pointer hint = 0) { + pointer allocate(size_type n, const void* hint = 0) { return reinterpret_cast( AlignedAllocate(Alignment, sizeof(value_type) * n)); } From ce53f69736efa9af3cd47baab3ac752509d0cecb Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 23 Dec 2020 14:25:36 +0100 Subject: [PATCH 036/478] fix: Empty CMake elseif --- util/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 7a3425f8da..e1ae91ad33 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -200,7 +200,7 @@ if(APPLE) process/process_memory_mac.cc process/process_memory_mac.h ) - elseif() + else() target_sources(crashpad_util PRIVATE ios/exception_processor.h ios/exception_processor.mm From 3fc9e71661c1b2388e4d33aa6eb19948bbb383e2 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 23 Dec 2020 14:50:17 +0100 Subject: [PATCH 037/478] fix: Link to UIKit framework on iOS --- util/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index e1ae91ad33..63b296f5d6 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -416,6 +416,11 @@ if(APPLE) "-framework Foundation" "-framework IOKit" ) + if(IOS) + target_link_libraries(crashpad_util PRIVATE + "-framework UIKit" + ) + endif() endif() if(LINUX) From a26ad17363f7f292b6ed1c382717b0d1928d4555 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 4 Jan 2021 13:00:42 +0100 Subject: [PATCH 038/478] cmake: Fix cross build from Mac x64 to Mac arm64 (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Romain Roffé --- util/CMakeLists.txt | 24 +++++++++++++++++++++++- util/mach/mig_gen.py | 7 ++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 63b296f5d6..ff9ae0c7bd 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -375,6 +375,22 @@ if(APPLE) endif() list(TRANSFORM includes PREPEND "--include=") + if(CMAKE_OSX_SYSROOT) + set(sdk --sdk ${CMAKE_OSX_SYSROOT}) + endif() + + # When building for Xcode, the `CMAKE_OSX_SYSROOT` is not set to a proper + # directory, but rather is `iphoneos`, which confuses `mig`. + # Also, Xcode uses a different `SDKROOT` depending on the `-sdk` flag + # provided to `xcodebuild`. + # Similarly, we don't know the arch at configure-time, because it changes + # at build time depending on the `-sdk` flag as well. + # We hack around this by consuming the arch list from the env. + if(XCODE) + set(archs --arch "FROM_ENV") + set(sdk --sdk "$SDKROOT") + endif() + # Create generate rule for each input file. Add each generated output # as a source to the target. foreach(input ${input_files}) @@ -387,7 +403,7 @@ if(APPLE) OUTPUT ${output_files} COMMAND - "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" ${archs} ${includes} "${input}" ${output_files} + "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" ${archs} ${sdk} ${includes} "${input}" ${output_files} DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ) @@ -410,6 +426,12 @@ target_link_libraries(crashpad_util ) if(APPLE) + get_property(archs TARGET crashpad_util PROPERTY OSX_ARCHITECTURES) + if (archs) + list(TRANSFORM archs PREPEND "-arch ") + set(CMAKE_ASM_FLAGS "${CFLAGS} ${archs}") + endif() + target_link_libraries(crashpad_util PRIVATE bsm "-framework CoreFoundation" diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py index 99b4f7ec6b..b3ef614e7a 100755 --- a/util/mach/mig_gen.py +++ b/util/mach/mig_gen.py @@ -83,7 +83,12 @@ def parse_args(args, multiple_arch=False): parser.add_argument('server_c') parser.add_argument('user_h') parser.add_argument('server_h') - return parser.parse_args(args) + + # This is a HACK to parse arch from env when cmake is configured to use xcode + parsed = parser.parse_args(args) + if multiple_arch and len(parsed.arch) == 1 and parsed.arch[0] == "FROM_ENV": + parsed.arch = os.environ.get("ARCHS", "").split(" ") + return parsed def main(args): From aeb8be5238ac48123ca89bb8a5ccaf3560f5bfc2 Mon Sep 17 00:00:00 2001 From: Siim Meerits Date: Mon, 11 Jan 2021 00:11:27 +0200 Subject: [PATCH 039/478] cmake: Install 'handler' and 'util' development header files. (#32) --- handler/CMakeLists.txt | 4 ++++ util/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 3288ac46b2..073aff2093 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -74,6 +74,10 @@ set_property(TARGET crashpad_handler_lib PROPERTY EXPORT_NAME handler) add_library(crashpad::handler_lib ALIAS crashpad_handler_lib) crashpad_install_target(crashpad_handler_lib) +crashpad_install_dev(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/handler" + FILES_MATCHING PATTERN "*.h" +) if(NOT IOS) add_executable(crashpad_handler WIN32 diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index ff9ae0c7bd..cb25aad393 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -487,3 +487,7 @@ set_property(TARGET crashpad_util PROPERTY EXPORT_NAME util) add_library(crashpad::util ALIAS crashpad_util) crashpad_install_target(crashpad_util) +crashpad_install_dev(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/util" + FILES_MATCHING PATTERN "*.h" +) From 3c9de32f2bf7878c10a47e5957d02b05465f25af Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 20 Jan 2021 12:47:47 +0100 Subject: [PATCH 040/478] fix: Add missing flags for zlib compilation (#22) --- third_party/zlib/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index 451433171f..2f9a87dedd 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -48,6 +48,10 @@ else() zlib/x86.c zlib/x86.h ) + + if(NOT MSVC) + target_compile_options(crashpad_zlib PRIVATE -msse4.2 -mpclmul) + endif() endif() target_compile_definitions(crashpad_zlib PUBLIC CRASHPAD_ZLIB_SOURCE_EMBEDDED From 358403ca327392337e77f3cc0a27766e3639e2d5 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 25 Jan 2021 11:39:50 +0100 Subject: [PATCH 041/478] update submodule and sync build files --- compat/CMakeLists.txt | 13 ------------- third_party/mini_chromium/mini_chromium | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt index 50be8a456e..e4f430360c 100644 --- a/compat/CMakeLists.txt +++ b/compat/CMakeLists.txt @@ -12,10 +12,7 @@ if(APPLE) ) else() list(APPEND COMPAT_SOURCES - non_mac/mach-o/loader.h non_mac/mach/mach.h - non_mac/mach/machine.h - non_mac/mach/vm_prot.h ) endif() @@ -85,12 +82,6 @@ else() ) endif() -if(NOT LINUX AND NOT ANDROID) - list(APPEND COMPAT_SOURCES - non_elf/elf.h - ) -endif() - if(APPLE) add_library(crashpad_compat INTERFACE) set(TI_TYPE "INTERFACE") @@ -117,8 +108,6 @@ endif() if(APPLE) target_include_directories(crashpad_compat ${TI_TYPE} "$") -else() - target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() if(IOS) @@ -127,8 +116,6 @@ endif() if(LINUX OR ANDROID) target_include_directories(crashpad_compat ${TI_TYPE} "$") -else() - target_include_directories(crashpad_compat ${TI_TYPE} "$") endif() if(ANDROID) diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index c748b289b8..12ea507eb7 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit c748b289b825056985f3dd3b36dc86c766d787ad +Subproject commit 12ea507eb719a54698e1429e91e84c65284805ab From ee06cb2b2d0f99bd432f00117ee3a676fc55d11b Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 25 Jan 2021 12:00:16 +0100 Subject: [PATCH 042/478] hardcode chromeos_buildflags --- third_party/mini_chromium/CMakeLists.txt | 4 ++++ .../mini_chromium/build/chromeos_buildflags.h | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 third_party/mini_chromium/build/chromeos_buildflags.h diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index cece468fc9..907ddc3bbf 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -4,6 +4,7 @@ function(mc_append_sources) target_sources(mini_chromium PRIVATE ${ARGN}) endfunction() +target_sources(mini_chromium PRIVATE build/chromeos_buildflags.h) mc_append_sources( ../build/build_config.h atomicops.h @@ -172,6 +173,9 @@ target_include_directories(mini_chromium PUBLIC "$" $ ) +target_include_directories(mini_chromium PUBLIC + "$" +) target_link_libraries(mini_chromium PRIVATE $ diff --git a/third_party/mini_chromium/build/chromeos_buildflags.h b/third_party/mini_chromium/build/chromeos_buildflags.h new file mode 100644 index 0000000000..c54f076845 --- /dev/null +++ b/third_party/mini_chromium/build/chromeos_buildflags.h @@ -0,0 +1,13 @@ +// This header should be generated by `build/write_buildflag_header.py`, +// but we rather hardcode it to simplify CMake scripts, as we do not +// support building on chromeos anyway. + +#ifndef MINI_CHROMIUM_BUILD_CHROMEOS_BUILDFLAGS_H_ +#define MINI_CHROMIUM_BUILD_CHROMEOS_BUILDFLAGS_H_ + +#include "build/buildflag.h" + +#define BUILDFLAG_INTERNAL_IS_CHROMEOS_LACROS() (0) +#define BUILDFLAG_INTERNAL_IS_CHROMEOS_ASH() (0) + +#endif // MINI_CHROMIUM_BUILD_CHROMEOS_BUILDFLAGS_H_ From cb520bd41fdea18a4d842efabeac61a2a5beaa61 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 26 Jan 2021 12:13:39 +0100 Subject: [PATCH 043/478] remove conflicting gitignore of lss --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1e9f1ec064..64507fc480 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ /third_party/linux/.cipd /third_party/linux/clang /third_party/linux/sysroot -/third_party/lss/lss /third_party/gyp/gyp /xcodebuild tags From e860f7f132163c0b52f405656ac1c8607a7d79ea Mon Sep 17 00:00:00 2001 From: daxpedda Date: Mon, 1 Mar 2021 10:23:00 +0100 Subject: [PATCH 044/478] fix: Fix cross-compilation from Intel to Apple Silicon MacOS. (#34) --- third_party/zlib/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index 2f9a87dedd..f912af5ed6 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -41,7 +41,13 @@ else() zlib/zutil.h zlib_crashpad.h ) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(x86)|(i[3-7]86)|(AMD64)") + if (APPLE) + get_property(archs TARGET crashpad_zlib PROPERTY OSX_ARCHITECTURES) + endif() + if(NOT archs) + set(archs ${CMAKE_SYSTEM_PROCESSOR}) + endif() + if(archs MATCHES "(x86_64)|(x86)|(i[3-7]86)|(AMD64)") target_sources(crashpad_zlib PRIVATE zlib/crc_folding.c zlib/fill_window_sse.c @@ -52,6 +58,8 @@ else() if(NOT MSVC) target_compile_options(crashpad_zlib PRIVATE -msse4.2 -mpclmul) endif() + else() + target_sources(crashpad_zlib PRIVATE zlib/simd_stub.c) endif() target_compile_definitions(crashpad_zlib PUBLIC CRASHPAD_ZLIB_SOURCE_EMBEDDED From bce6d14d075f0b522c2744a186cae2c6c01f76dc Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 12 Apr 2021 04:27:42 -0400 Subject: [PATCH 045/478] fix: CMAKE_ASM_FLAGS with multiple OSX_ARCHITECTURES (#35) --- util/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index cb25aad393..84b5be6de8 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -429,7 +429,8 @@ if(APPLE) get_property(archs TARGET crashpad_util PROPERTY OSX_ARCHITECTURES) if (archs) list(TRANSFORM archs PREPEND "-arch ") - set(CMAKE_ASM_FLAGS "${CFLAGS} ${archs}") + list(JOIN archs " " archs_str) + set(CMAKE_ASM_FLAGS "${CFLAGS} ${archs_str}") endif() target_link_libraries(crashpad_util PRIVATE From deb4dceb4048c940ca98870c410d6fc03281a925 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 12 Apr 2021 16:14:21 +0200 Subject: [PATCH 046/478] Sync CMake and submodules --- client/CMakeLists.txt | 1 + third_party/mini_chromium/CMakeLists.txt | 2 -- third_party/mini_chromium/mini_chromium | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 11ba9f4edc..839476f664 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -30,6 +30,7 @@ if(IOS) target_sources(crashpad_client PRIVATE crash_report_database_mac.mm crashpad_client_ios.cc + simulate_crash_ios.h ) endif() diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 907ddc3bbf..b81cd3b098 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -51,8 +51,6 @@ mc_append_sources( scoped_clear_last_error.h scoped_generic.h stl_util.h - strings/string16.cc - strings/string16.h strings/string_number_conversions.cc strings/string_number_conversions.h strings/string_piece.h diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 12ea507eb7..329ca82f73 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 12ea507eb719a54698e1429e91e84c65284805ab +Subproject commit 329ca82f73a592d832e79334bed842fba85b9fdd From fdbe4d7b1053939f2c77193d8e854de5a3c93e17 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 20 Apr 2021 12:12:11 +0200 Subject: [PATCH 047/478] fix: Avoid EXPORT_NAME clash (#37) --- handler/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 073aff2093..36c77aa897 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -110,7 +110,7 @@ if(NOT IOS) endif() endif() - set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME handler) + set_property(TARGET crashpad_handler PROPERTY EXPORT_NAME crashpad_handler) add_executable(crashpad::handler ALIAS crashpad_handler) install(TARGETS crashpad_handler EXPORT crashpad_export From 71bcaad4cf30294b8de1bfa02064ab629437163b Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 16 May 2021 14:47:25 +0200 Subject: [PATCH 048/478] fix: Add missing installed header (build/chromeos_buildflags.h) (#38) --- third_party/mini_chromium/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index b81cd3b098..f8c85ea7cf 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -207,3 +207,7 @@ crashpad_install_dev(DIRECTORY mini_chromium DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad" FILES_MATCHING PATTERN "*.h" ) +crashpad_install_dev(DIRECTORY build + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/crashpad/mini_chromium" + FILES_MATCHING PATTERN "*.h" +) From 5cf3032b2281cf0928acc8bccf69f91ccf26b939 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 14 Jun 2021 12:41:05 +0200 Subject: [PATCH 049/478] build: Sync CMake files with GN --- client/CMakeLists.txt | 2 +- handler/CMakeLists.txt | 8 ++++++-- snapshot/CMakeLists.txt | 26 +++++++++++++----------- third_party/mini_chromium/CMakeLists.txt | 2 +- third_party/mini_chromium/mini_chromium | 2 +- util/CMakeLists.txt | 17 ++++++++++++++++ 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 839476f664..702f002447 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -40,8 +40,8 @@ if(LINUX OR ANDROID) simulate_crash_linux.h client_argv_handling.cc client_argv_handling.h - crashpad_info_note.S crash_report_database_generic.cc + crashpad_info_note.S ) endif() diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 36c77aa897..75f8bbb41e 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -11,14 +11,18 @@ add_library(crashpad_handler_lib STATIC user_stream_data_source.h ) +if(APPLE) + target_sources(crashpad_handler_lib PRIVATE + mac/file_limit_annotation.cc + mac/file_limit_annotation.h + ) +endif() if(APPLE AND NOT IOS) target_sources(crashpad_handler_lib PRIVATE mac/crash_report_exception_handler.cc mac/crash_report_exception_handler.h mac/exception_handler_server.cc mac/exception_handler_server.h - mac/file_limit_annotation.cc - mac/file_limit_annotation.h ) endif() diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 5da894b76a..10679a1135 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -84,18 +84,20 @@ elseif(IOS) target_sources(crashpad_snapshot PRIVATE posix/timezone.cc posix/timezone.h - ios/exception_snapshot_ios.cc - ios/exception_snapshot_ios.h - ios/memory_snapshot_ios.cc - ios/memory_snapshot_ios.h - ios/module_snapshot_ios.cc - ios/module_snapshot_ios.h - ios/process_snapshot_ios.cc - ios/process_snapshot_ios.h - ios/system_snapshot_ios.cc - ios/system_snapshot_ios.h - ios/thread_snapshot_ios.cc - ios/thread_snapshot_ios.h + ios/exception_snapshot_ios_intermediate_dump.cc + ios/exception_snapshot_ios_intermediate_dump.h + ios/intermediate_dump_reader_util.cc + ios/intermediate_dump_reader_util.h + ios/memory_snapshot_ios_intermediate_dump.cc + ios/memory_snapshot_ios_intermediate_dump.h + ios/module_snapshot_ios_intermediate_dump.cc + ios/module_snapshot_ios_intermediate_dump.h + ios/process_snapshot_ios_intermediate_dump.cc + ios/process_snapshot_ios_intermediate_dump.h + ios/system_snapshot_ios_intermediate_dump.cc + ios/system_snapshot_ios_intermediate_dump.h + ios/thread_snapshot_ios_intermediate_dump.cc + ios/thread_snapshot_ios_intermediate_dump.h mac/cpu_context_mac.cc mac/cpu_context_mac.h ) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index f8c85ea7cf..83a0ef875f 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -15,6 +15,7 @@ mc_append_sources( check.h check_op.h compiler_specific.h + cxx17_backports.h debug/alias.cc debug/alias.h files/file_path.cc @@ -50,7 +51,6 @@ mc_append_sources( rand_util.h scoped_clear_last_error.h scoped_generic.h - stl_util.h strings/string_number_conversions.cc strings/string_number_conversions.h strings/string_piece.h diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 329ca82f73..2470faf722 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 329ca82f73a592d832e79334bed842fba85b9fdd +Subproject commit 2470faf722b0fd259ca11c045fdb370e09037c4e diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 84b5be6de8..896d9ef0b7 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -204,8 +204,25 @@ if(APPLE) target_sources(crashpad_util PRIVATE ios/exception_processor.h ios/exception_processor.mm + ios/ios_intermediate_dump_data.cc + ios/ios_intermediate_dump_data.h + ios/ios_intermediate_dump_format.h + ios/ios_intermediate_dump_list.cc + ios/ios_intermediate_dump_list.h + ios/ios_intermediate_dump_map.cc + ios/ios_intermediate_dump_map.h + ios/ios_intermediate_dump_object.cc + ios/ios_intermediate_dump_object.h + ios/ios_intermediate_dump_reader.cc + ios/ios_intermediate_dump_reader.h + ios/ios_intermediate_dump_writer.cc + ios/ios_intermediate_dump_writer.h ios/ios_system_data_collector.h ios/ios_system_data_collector.mm + ios/raw_logging.cc + ios/raw_logging.h + ios/scoped_vm_read.cc + ios/scoped_vm_read.h ) endif() endif() From 7a31c8491ec771d7f7577c63585e2c4c4d49c03c Mon Sep 17 00:00:00 2001 From: Yuriy Levchenko Date: Wed, 14 Jul 2021 15:56:58 +0300 Subject: [PATCH 050/478] fix(mingw): Use correct char16 type for utf_string_conversion_utils (#41) --- .../mini_chromium/utf_string_conversion_utils.mingw.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc b/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc index 6baf7b452d..4184adf649 100644 --- a/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc +++ b/third_party/mini_chromium/utf_string_conversion_utils.mingw.cc @@ -21,7 +21,7 @@ bool ReadUnicodeCharacter(const char* src, return IsValidCodepoint(code_point); } -bool ReadUnicodeCharacter(const char16* src, +bool ReadUnicodeCharacter(const char16_t* src, int32_t src_len, int32_t* char_index, uint32_t* code_point) { @@ -58,9 +58,9 @@ size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) { return char_offset - original_char_offset; } -size_t WriteUnicodeCharacter(uint32_t code_point, string16* output) { +size_t WriteUnicodeCharacter(uint32_t code_point, std::u16string* output) { if (CBU16_LENGTH(code_point) == 1) { - output->push_back(static_cast(code_point)); + output->push_back(static_cast(code_point)); return 1; } size_t char_offset = output->length(); @@ -84,7 +84,7 @@ void PrepareForUTF8Output(const CHAR* src, } template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*); -// template void PrepareForUTF8Output(const char16*, size_t, std::string*); +template void PrepareForUTF8Output(const char16_t*, size_t, std::string*); template void PrepareForUTF16Or32Output(const char* src, @@ -100,6 +100,6 @@ void PrepareForUTF16Or32Output(const char* src, } } -template void PrepareForUTF16Or32Output(const char*, size_t, string16*); +template void PrepareForUTF16Or32Output(const char*, size_t, std::u16string*); } // namespace base From 0d75b0631bddb5fdb012a143874e2577ec304546 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Wed, 28 Jul 2021 13:37:10 +0200 Subject: [PATCH 051/478] Update mini_chromium submodule --- third_party/mini_chromium/CMakeLists.txt | 6 +++--- third_party/mini_chromium/mini_chromium | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 83a0ef875f..216f3d477f 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -28,6 +28,7 @@ mc_append_sources( logging.h macros.h memory/free_deleter.h + memory/page_size.h memory/scoped_policy.h metrics/histogram_functions.h metrics/histogram_macros.h @@ -46,7 +47,6 @@ mc_append_sources( numerics/safe_math_shared_impl.h process/memory.cc process/memory.h - process/process_metrics.h rand_util.cc rand_util.h scoped_clear_last_error.h @@ -124,7 +124,7 @@ endif() if(WIN32) mc_append_sources( - process/process_metrics_win.cc + memory/page_size_win.cc scoped_clear_last_error_win.cc strings/string_util_win.cc strings/string_util_win.h @@ -134,10 +134,10 @@ if(WIN32) else() mc_append_sources( files/file_util_posix.cc + memory/page_size_posix.cc posix/eintr_wrapper.h posix/safe_strerror.cc posix/safe_strerror.h - process/process_metrics_posix.cc strings/string_util_posix.h synchronization/condition_variable_posix.cc synchronization/lock_impl_posix.cc diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 2470faf722..f9ae4322df 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 2470faf722b0fd259ca11c045fdb370e09037c4e +Subproject commit f9ae4322dfc5bcc14cc82d6005107f3b75ca2059 From 59422f80649b513ae9b1ec0b3a7f97b5f51d44e2 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 6 Sep 2021 13:52:20 +0200 Subject: [PATCH 052/478] feat: Write client-side stacktraces to the minidump --- minidump/CMakeLists.txt | 2 + minidump/minidump_extensions.h | 15 ++- minidump/minidump_file_writer.cc | 11 ++- minidump/minidump_stacktrace_writer.cc | 121 +++++++++++++++++++++++++ minidump/minidump_stacktrace_writer.h | 102 +++++++++++++++++++++ 5 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 minidump/minidump_stacktrace_writer.cc create mode 100644 minidump/minidump_stacktrace_writer.h diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt index 1bf972ab98..e0b8f9a04e 100644 --- a/minidump/CMakeLists.txt +++ b/minidump/CMakeLists.txt @@ -30,6 +30,8 @@ add_library(crashpad_minidump STATIC minidump_rva_list_writer.h minidump_simple_string_dictionary_writer.cc minidump_simple_string_dictionary_writer.h + minidump_stacktrace_writer.cc + minidump_stacktrace_writer.h minidump_stream_writer.cc minidump_stream_writer.h minidump_string_writer.cc diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 97276d529a..21993eec1b 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -15,9 +15,9 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_ -#include #include #include +#include #include #include "base/compiler_specific.h" @@ -32,7 +32,7 @@ // disable it with other silly warnings in the build files. See: // https://connect.microsoft.com/VisualStudio/feedback/details/1114440 #pragma warning(push) -#pragma warning(disable: 4200) +#pragma warning(disable : 4200) #define PACKED #pragma pack(push, 1) @@ -105,6 +105,14 @@ enum MinidumpStreamType : uint32_t { //! \brief The last reserved crashpad stream. kMinidumpStreamTypeCrashpadLastReservedStream = 0x4350ffff, + + // 0x5379 = "Sy" + + //! \brief The stream type for client-side stack traces. + kMinidumpStreamTypeSentryStackTraces = 0x53790001, + + //! \brief The last reserved Sentry stream. + kMinidumpStreamTypeSentryLastReservedStream = 0x5379ffff, }; //! \brief A variable-length UTF-8-encoded string carried within a minidump @@ -439,8 +447,7 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { report_id(), client_id(), simple_annotations(), - module_list() { - } + module_list() {} //! \brief The structure’s currently-defined version number. //! diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 6727a0dcda..f12a84a401 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -24,8 +24,8 @@ #include "minidump/minidump_memory_writer.h" #include "minidump/minidump_misc_info_writer.h" #include "minidump/minidump_module_writer.h" +#include "minidump/minidump_stacktrace_writer.h" #include "minidump/minidump_system_info_writer.h" -#include "minidump/minidump_thread_id_map.h" #include "minidump/minidump_thread_writer.h" #include "minidump/minidump_unloaded_module_writer.h" #include "minidump/minidump_user_extension_stream_data_source.h" @@ -51,8 +51,7 @@ MinidumpFileWriter::MinidumpFileWriter() header_.Flags = MiniDumpNormal; } -MinidumpFileWriter::~MinidumpFileWriter() { -} +MinidumpFileWriter::~MinidumpFileWriter() {} void MinidumpFileWriter::InitializeFromSnapshot( const ProcessSnapshot* process_snapshot) { @@ -104,6 +103,12 @@ void MinidumpFileWriter::InitializeFromSnapshot( add_stream_result = AddStream(std::move(module_list)); DCHECK(add_stream_result); + auto stacktrace_list = std::make_unique(); + stacktrace_list->InitializeFromSnapshot(process_snapshot->Threads(), + thread_id_map); + add_stream_result = AddStream(std::move(stacktrace_list)); + DCHECK(add_stream_result); + auto unloaded_modules = process_snapshot->UnloadedModules(); if (!unloaded_modules.empty()) { auto unloaded_module_list = diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc new file mode 100644 index 0000000000..f9c69c9f59 --- /dev/null +++ b/minidump/minidump_stacktrace_writer.cc @@ -0,0 +1,121 @@ + +#include "minidump/minidump_stacktrace_writer.h" + +#include + +#include +#include + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "minidump/minidump_string_writer.h" +#include "minidump/minidump_writer_util.h" +#include "snapshot/thread_snapshot.h" +#include "util/file/file_writer.h" +#include "util/misc/implicit_cast.h" +#include "util/numeric/in_range_cast.h" +#include "util/numeric/safe_assignment.h" + +namespace crashpad { + +MinidumpStacktraceListWriter::MinidumpStacktraceListWriter() + : MinidumpStreamWriter(), + threads_(), + frames_(), + symbol_bytes_(), + stacktrace_header_() {} + +MinidumpStacktraceListWriter::~MinidumpStacktraceListWriter() {} + +void MinidumpStacktraceListWriter::InitializeFromSnapshot( + const std::vector& thread_snapshots, + const MinidumpThreadIDMap& thread_id_map) { + DCHECK_EQ(state(), kStateMutable); + + DCHECK(threads_.empty()); + DCHECK(frames_.empty()); + DCHECK(symbol_bytes_.empty()); + + for (auto thread_snapshot : thread_snapshots) { + internal::RawThread thread; + thread.thread_id = thread_snapshot->ThreadID(); + thread.start_frame = frames_.size(); + + // TODO: Create a stub that will later return a real stack trace: + // That would be https://getsentry.atlassian.net/browse/NATIVE-198 + // auto frames = thread_snapshot->StackTrace(); + std::vector frames; + frames.emplace_back(0xfff70001, std::string("uiaeo")); + frames.emplace_back(0xfff70002, std::string("snrtdy")); + + for (auto frame_snapshot : frames) { + internal::RawFrame frame; + frame.instruction_addr = frame_snapshot.InstructionAddr(); + frame.symbol_offset = symbol_bytes_.size(); + + auto symbol = frame_snapshot.Symbol(); + + symbol_bytes_.reserve(symbol.size()); + symbol_bytes_.insert(symbol_bytes_.end(), symbol.begin(), symbol.end()); + + frame.symbol_len = symbol.size(); + + frames_.push_back(frame); + } + + thread.num_frames = frames_.size() - thread.start_frame; + + threads_.push_back(thread); + } + + stacktrace_header_.version = 1; + stacktrace_header_.num_threads = threads_.size(); + stacktrace_header_.num_frames = frames_.size(); + stacktrace_header_.symbol_bytes = symbol_bytes_.size(); +} + +size_t MinidumpStacktraceListWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + + return sizeof(stacktrace_header_) + + threads_.size() * sizeof(internal::RawThread) + + frames_.size() * sizeof(internal::RawFrame) + symbol_bytes_.size(); +} + +size_t MinidumpStacktraceListWriter::Alignment() { + // because we are writing `uint64_t` that are 8-byte aligned + return 8; +} + +bool MinidumpStacktraceListWriter::WriteObject( + FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + + WritableIoVec iov; + // header, threads, frames, symbol_bytes + std::vector iovecs(4); + + iov.iov_base = &stacktrace_header_; + iov.iov_len = sizeof(stacktrace_header_); + iovecs.push_back(iov); + + iov.iov_base = &threads_.front(); + iov.iov_len = threads_.size() * sizeof(internal::RawThread); + iovecs.push_back(iov); + + iov.iov_base = &frames_.front(); + iov.iov_len = frames_.size() * sizeof(internal::RawFrame); + iovecs.push_back(iov); + + iov.iov_base = &symbol_bytes_.front(); + iov.iov_len = symbol_bytes_.size(); + iovecs.push_back(iov); + + return file_writer->WriteIoVec(&iovecs); +} + +MinidumpStreamType MinidumpStacktraceListWriter::StreamType() const { + return kMinidumpStreamTypeSentryStackTraces; +} + +} // namespace crashpad diff --git a/minidump/minidump_stacktrace_writer.h b/minidump/minidump_stacktrace_writer.h new file mode 100644 index 0000000000..d7816f9e18 --- /dev/null +++ b/minidump/minidump_stacktrace_writer.h @@ -0,0 +1,102 @@ +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_STACKTRACE_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_STACKTRACE_WRITER_H_ + +#include +#include + +#include +#include +#include + +#include "base/macros.h" +#include "minidump/minidump_extensions.h" +#include "minidump/minidump_stream_writer.h" +#include "minidump/minidump_thread_id_map.h" +#include "minidump/minidump_writable.h" + +namespace crashpad { + +namespace internal { + +struct Header { + uint32_t version; + uint32_t num_threads; + uint32_t num_frames; + uint32_t symbol_bytes; +}; + +struct RawThread { + uint64_t thread_id; + uint32_t start_frame; + uint32_t num_frames; +}; + +struct RawFrame { + uint64_t instruction_addr; + uint32_t symbol_offset; + uint32_t symbol_len; +}; + +} // namespace internal + +// TODO: Create a stub that will later return a real stack trace: +// `ThreadSnapshot.StackTrace` would need to return a +// `const std::vector&`, so that followup will also move +// that type to a more appropriate place. +// That would be https://getsentry.atlassian.net/browse/NATIVE-198 +class FrameSnapshot { + public: + FrameSnapshot(uint64_t instruction_addr, std::string symbol) + : instruction_addr_(instruction_addr), symbol_(symbol) {} + + uint64_t InstructionAddr() const { return instruction_addr_; }; + const std::string& Symbol() const { return symbol_; }; + + private: + uint64_t instruction_addr_; + std::string symbol_; +}; + +class ThreadSnapshot; + +//! \brief The writer for our custom client-side stacktraces stream in a +//! minidump file. +class MinidumpStacktraceListWriter final + : public internal::MinidumpStreamWriter { + public: + MinidumpStacktraceListWriter(); + ~MinidumpStacktraceListWriter() override; + + //! \brief TODO + //! + //! \param[in] thread_snapshots The thread snapshots to use as source data. + //! \param[in] thread_id_map A MinidumpThreadIDMap to be consulted to + //! determine the 32-bit minidump thread ID to use for the thread + //! identified by \a thread_snapshots. + void InitializeFromSnapshot( + const std::vector& thread_snapshots, + const MinidumpThreadIDMap& thread_id_map); + + protected: + // MinidumpWritable: + // bool Freeze() override; + size_t SizeOfObject() override; + size_t Alignment() override; + // std::vector Children() override; + bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpStreamWriter: + MinidumpStreamType StreamType() const override; + + private: + std::vector threads_; + std::vector frames_; + std::vector symbol_bytes_; + internal::Header stacktrace_header_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpStacktraceListWriter); +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_STACKTRACE_WRITER_H_ From 19176d1babc51fd3cf82c125d964439d9e099a7e Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 7 Sep 2021 11:18:17 +0200 Subject: [PATCH 053/478] update cmake and submodules --- client/CMakeLists.txt | 4 ++++ third_party/mini_chromium/mini_chromium | 2 +- util/CMakeLists.txt | 2 -- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 702f002447..5357c8624f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -30,6 +30,10 @@ if(IOS) target_sources(crashpad_client PRIVATE crash_report_database_mac.mm crashpad_client_ios.cc + ios_handler/exception_processor.h + ios_handler/exception_processor.mm + ios_handler/in_process_intermediate_dump_handler.cc + ios_handler/in_process_intermediate_dump_handler.h simulate_crash_ios.h ) endif() diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index f9ae4322df..8f7a60f2c6 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit f9ae4322dfc5bcc14cc82d6005107f3b75ca2059 +Subproject commit 8f7a60f2c637f2a3c5d25f320739b3de7c2e325d diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 896d9ef0b7..28218b856e 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -202,8 +202,6 @@ if(APPLE) ) else() target_sources(crashpad_util PRIVATE - ios/exception_processor.h - ios/exception_processor.mm ios/ios_intermediate_dump_data.cc ios/ios_intermediate_dump_data.h ios/ios_intermediate_dump_format.h From a47690d05ae493fb877276b1e8b36b7ff14d01d8 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 7 Sep 2021 15:07:44 +0200 Subject: [PATCH 054/478] revert automatic include formatting --- minidump/minidump_extensions.h | 7 ++++--- minidump/minidump_file_writer.cc | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 21993eec1b..db0c33ec5e 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -15,9 +15,9 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_ +#include #include #include -#include #include #include "base/compiler_specific.h" @@ -32,7 +32,7 @@ // disable it with other silly warnings in the build files. See: // https://connect.microsoft.com/VisualStudio/feedback/details/1114440 #pragma warning(push) -#pragma warning(disable : 4200) +#pragma warning(disable: 4200) #define PACKED #pragma pack(push, 1) @@ -447,7 +447,8 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { report_id(), client_id(), simple_annotations(), - module_list() {} + module_list() { + } //! \brief The structure’s currently-defined version number. //! diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index f12a84a401..8cd23f241f 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -26,6 +26,7 @@ #include "minidump/minidump_module_writer.h" #include "minidump/minidump_stacktrace_writer.h" #include "minidump/minidump_system_info_writer.h" +#include "minidump/minidump_thread_id_map.h" #include "minidump/minidump_thread_writer.h" #include "minidump/minidump_unloaded_module_writer.h" #include "minidump/minidump_user_extension_stream_data_source.h" From 6dd26ef75c1f477b63459ac5599ff2edab12c4be Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 7 Sep 2021 15:35:15 +0200 Subject: [PATCH 055/478] remove unused includes, explicitly cast indices and nums --- minidump/minidump_stacktrace_writer.cc | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc index f9c69c9f59..dd79261ba5 100644 --- a/minidump/minidump_stacktrace_writer.cc +++ b/minidump/minidump_stacktrace_writer.cc @@ -7,14 +7,8 @@ #include #include "base/logging.h" -#include "base/numerics/safe_conversions.h" -#include "minidump/minidump_string_writer.h" -#include "minidump/minidump_writer_util.h" #include "snapshot/thread_snapshot.h" #include "util/file/file_writer.h" -#include "util/misc/implicit_cast.h" -#include "util/numeric/in_range_cast.h" -#include "util/numeric/safe_assignment.h" namespace crashpad { @@ -39,7 +33,7 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( for (auto thread_snapshot : thread_snapshots) { internal::RawThread thread; thread.thread_id = thread_snapshot->ThreadID(); - thread.start_frame = frames_.size(); + thread.start_frame = (uint32_t)frames_.size(); // TODO: Create a stub that will later return a real stack trace: // That would be https://getsentry.atlassian.net/browse/NATIVE-198 @@ -51,27 +45,27 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( for (auto frame_snapshot : frames) { internal::RawFrame frame; frame.instruction_addr = frame_snapshot.InstructionAddr(); - frame.symbol_offset = symbol_bytes_.size(); + frame.symbol_offset = (uint32_t)symbol_bytes_.size(); auto symbol = frame_snapshot.Symbol(); symbol_bytes_.reserve(symbol.size()); symbol_bytes_.insert(symbol_bytes_.end(), symbol.begin(), symbol.end()); - frame.symbol_len = symbol.size(); + frame.symbol_len = (uint32_t)symbol.size(); frames_.push_back(frame); } - thread.num_frames = frames_.size() - thread.start_frame; + thread.num_frames = (uint32_t)frames_.size() - thread.start_frame; threads_.push_back(thread); } stacktrace_header_.version = 1; - stacktrace_header_.num_threads = threads_.size(); - stacktrace_header_.num_frames = frames_.size(); - stacktrace_header_.symbol_bytes = symbol_bytes_.size(); + stacktrace_header_.num_threads = (uint32_t)threads_.size(); + stacktrace_header_.num_frames = (uint32_t)frames_.size(); + stacktrace_header_.symbol_bytes = (uint32_t)symbol_bytes_.size(); } size_t MinidumpStacktraceListWriter::SizeOfObject() { From 0bbcdfd2c490e96a9466ed93a8bded9f96cd9f70 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 7 Sep 2021 16:27:15 +0200 Subject: [PATCH 056/478] Make thread_id 32bits and fix alignment --- minidump/minidump_stacktrace_writer.cc | 45 +++++++++++++++++++++++--- minidump/minidump_stacktrace_writer.h | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc index dd79261ba5..df8c703680 100644 --- a/minidump/minidump_stacktrace_writer.cc +++ b/minidump/minidump_stacktrace_writer.cc @@ -12,6 +12,15 @@ namespace crashpad { +size_t align_to_8(size_t size) { + size_t rest = size % 8; + if (rest == 0) { + return 0; + } else { + return 8 - rest; + } +} + MinidumpStacktraceListWriter::MinidumpStacktraceListWriter() : MinidumpStreamWriter(), threads_(), @@ -32,7 +41,10 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( for (auto thread_snapshot : thread_snapshots) { internal::RawThread thread; - thread.thread_id = thread_snapshot->ThreadID(); + + auto thread_id_it = thread_id_map.find(thread_snapshot->ThreadID()); + DCHECK(thread_id_it != thread_id_map.end()); + thread.thread_id = thread_id_it->second; thread.start_frame = (uint32_t)frames_.size(); // TODO: Create a stub that will later return a real stack trace: @@ -71,9 +83,14 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( size_t MinidumpStacktraceListWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); - return sizeof(stacktrace_header_) + - threads_.size() * sizeof(internal::RawThread) + - frames_.size() * sizeof(internal::RawFrame) + symbol_bytes_.size(); + size_t header_size = sizeof(stacktrace_header_); + header_size += align_to_8(header_size); + size_t threads_size = threads_.size() * sizeof(internal::RawThread); + threads_size += align_to_8(threads_size); + size_t frames_size = frames_.size() * sizeof(internal::RawFrame); + frames_size += align_to_8(frames_size); + + return header_size + threads_size + frames_size + symbol_bytes_.size(); } size_t MinidumpStacktraceListWriter::Alignment() { @@ -85,6 +102,7 @@ bool MinidumpStacktraceListWriter::WriteObject( FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); + uint64_t padding = 0; WritableIoVec iov; // header, threads, frames, symbol_bytes std::vector iovecs(4); @@ -93,14 +111,33 @@ bool MinidumpStacktraceListWriter::WriteObject( iov.iov_len = sizeof(stacktrace_header_); iovecs.push_back(iov); + // align the length of iov to a multiple of 8 and write zeros as padding + iov.iov_base = &padding; + iov.iov_len = align_to_8(iov.iov_len); + if (iov.iov_len > 0) { + iovecs.push_back(iov); + } + iov.iov_base = &threads_.front(); iov.iov_len = threads_.size() * sizeof(internal::RawThread); iovecs.push_back(iov); + iov.iov_base = &padding; + iov.iov_len = align_to_8(iov.iov_len); + if (iov.iov_len > 0) { + iovecs.push_back(iov); + } + iov.iov_base = &frames_.front(); iov.iov_len = frames_.size() * sizeof(internal::RawFrame); iovecs.push_back(iov); + iov.iov_base = &padding; + iov.iov_len = align_to_8(iov.iov_len); + if (iov.iov_len > 0) { + iovecs.push_back(iov); + } + iov.iov_base = &symbol_bytes_.front(); iov.iov_len = symbol_bytes_.size(); iovecs.push_back(iov); diff --git a/minidump/minidump_stacktrace_writer.h b/minidump/minidump_stacktrace_writer.h index d7816f9e18..b6984acb67 100644 --- a/minidump/minidump_stacktrace_writer.h +++ b/minidump/minidump_stacktrace_writer.h @@ -26,7 +26,7 @@ struct Header { }; struct RawThread { - uint64_t thread_id; + uint32_t thread_id; uint32_t start_frame; uint32_t num_frames; }; From 1fa28f4edb6c3dcb7d611c0fc7f730d0cdb423bd Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 8 Sep 2021 15:25:05 +0200 Subject: [PATCH 057/478] Remove dummy frames --- minidump/minidump_stacktrace_writer.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc index df8c703680..e85ae183b5 100644 --- a/minidump/minidump_stacktrace_writer.cc +++ b/minidump/minidump_stacktrace_writer.cc @@ -51,8 +51,6 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( // That would be https://getsentry.atlassian.net/browse/NATIVE-198 // auto frames = thread_snapshot->StackTrace(); std::vector frames; - frames.emplace_back(0xfff70001, std::string("uiaeo")); - frames.emplace_back(0xfff70002, std::string("snrtdy")); for (auto frame_snapshot : frames) { internal::RawFrame frame; From a95e88e031e3665ae0a6d06b05ad3737671f3f60 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Mon, 6 Sep 2021 15:16:34 +0200 Subject: [PATCH 058/478] Add StackTrace method to ThreadSnapshot --- minidump/minidump_stacktrace_writer.cc | 5 +--- minidump/minidump_stacktrace_writer.h | 18 --------------- snapshot/thread_snapshot.h | 32 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc index e85ae183b5..cc1bb70eb6 100644 --- a/minidump/minidump_stacktrace_writer.cc +++ b/minidump/minidump_stacktrace_writer.cc @@ -47,10 +47,7 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( thread.thread_id = thread_id_it->second; thread.start_frame = (uint32_t)frames_.size(); - // TODO: Create a stub that will later return a real stack trace: - // That would be https://getsentry.atlassian.net/browse/NATIVE-198 - // auto frames = thread_snapshot->StackTrace(); - std::vector frames; + std::vector frames = thread_snapshot->StackTrace(); for (auto frame_snapshot : frames) { internal::RawFrame frame; diff --git a/minidump/minidump_stacktrace_writer.h b/minidump/minidump_stacktrace_writer.h index b6984acb67..e1a4963ca5 100644 --- a/minidump/minidump_stacktrace_writer.h +++ b/minidump/minidump_stacktrace_writer.h @@ -39,24 +39,6 @@ struct RawFrame { } // namespace internal -// TODO: Create a stub that will later return a real stack trace: -// `ThreadSnapshot.StackTrace` would need to return a -// `const std::vector&`, so that followup will also move -// that type to a more appropriate place. -// That would be https://getsentry.atlassian.net/browse/NATIVE-198 -class FrameSnapshot { - public: - FrameSnapshot(uint64_t instruction_addr, std::string symbol) - : instruction_addr_(instruction_addr), symbol_(symbol) {} - - uint64_t InstructionAddr() const { return instruction_addr_; }; - const std::string& Symbol() const { return symbol_; }; - - private: - uint64_t instruction_addr_; - std::string symbol_; -}; - class ThreadSnapshot; //! \brief The writer for our custom client-side stacktraces stream in a diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 4d732578e5..37791e00af 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -24,10 +24,33 @@ namespace crashpad { struct CPUContext; class MemorySnapshot; +// TODO: Create a stub that will later return a real stack trace: +// `ThreadSnapshot.StackTrace` would need to return a +// `const std::vector&`. +// That would be https://getsentry.atlassian.net/browse/NATIVE-198 +class FrameSnapshot { + public: + FrameSnapshot(uint64_t instruction_addr, std::string symbol) + : instruction_addr_(instruction_addr), symbol_(symbol) {} + + uint64_t InstructionAddr() const { return instruction_addr_; }; + const std::string& Symbol() const { return symbol_; }; + + private: + uint64_t instruction_addr_; + std::string symbol_; +}; + //! \brief An abstract interface to a snapshot representing a thread //! (lightweight process) present in a snapshot process. class ThreadSnapshot { public: + ThreadSnapshot() { + frames_ = std::vector(); + frames_.emplace_back(0xfff70001, std::string("uiaeo")); + frames_.emplace_back(0xfff70002, std::string("snrtdy")); + } + virtual ~ThreadSnapshot() {} //! \brief Returns a CPUContext object corresponding to the thread’s CPU @@ -73,6 +96,15 @@ class ThreadSnapshot { //! are scoped to the lifetime of the ThreadSnapshot object that they //! were obtained from. virtual std::vector ExtraMemory() const = 0; + + // TODO: This should return a `const std::vector&`. + const std::vector& StackTrace() const { + return frames_; + } + + private: + std::vector frames_; + }; } // namespace crashpad From 894ba6414bc9d94ca559780b47b120ac10c33894 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 7 Sep 2021 11:11:51 +0200 Subject: [PATCH 059/478] Add missing include --- snapshot/thread_snapshot.h | 1 + 1 file changed, 1 insertion(+) diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 37791e00af..c567aac81c 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -18,6 +18,7 @@ #include #include +#include namespace crashpad { From 39cf7b17e370dc723b349288c4ccb75b8b5f11b6 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 7 Sep 2021 15:47:14 +0200 Subject: [PATCH 060/478] Remove obsolete comment --- snapshot/thread_snapshot.h | 1 - 1 file changed, 1 deletion(-) diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index c567aac81c..09f5512bfc 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -98,7 +98,6 @@ class ThreadSnapshot { //! were obtained from. virtual std::vector ExtraMemory() const = 0; - // TODO: This should return a `const std::vector&`. const std::vector& StackTrace() const { return frames_; } From a61bfefd5a58e24a3a22aa9d6cd37daba59017d6 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 8 Sep 2021 15:24:21 +0200 Subject: [PATCH 061/478] Remove dummy frames --- snapshot/thread_snapshot.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 09f5512bfc..8606e42403 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -46,11 +46,7 @@ class FrameSnapshot { //! (lightweight process) present in a snapshot process. class ThreadSnapshot { public: - ThreadSnapshot() { - frames_ = std::vector(); - frames_.emplace_back(0xfff70001, std::string("uiaeo")); - frames_.emplace_back(0xfff70002, std::string("snrtdy")); - } + ThreadSnapshot() : frames_() {} virtual ~ThreadSnapshot() {} @@ -102,7 +98,7 @@ class ThreadSnapshot { return frames_; } - private: + protected: std::vector frames_; }; From 777fb6ae933f53a6d04ea1b28f749bb8f18684d8 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 8 Sep 2021 16:29:10 +0200 Subject: [PATCH 062/478] Remove comment --- snapshot/thread_snapshot.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 8606e42403..0251fbfca6 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -25,10 +25,6 @@ namespace crashpad { struct CPUContext; class MemorySnapshot; -// TODO: Create a stub that will later return a real stack trace: -// `ThreadSnapshot.StackTrace` would need to return a -// `const std::vector&`. -// That would be https://getsentry.atlassian.net/browse/NATIVE-198 class FrameSnapshot { public: FrameSnapshot(uint64_t instruction_addr, std::string symbol) From 725271e15e424cc79a5d528eee5b2806c8a502ac Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 11 Oct 2021 14:07:03 +0200 Subject: [PATCH 063/478] feat: Do client-side stackwalking on Windows (NATIVE-150) (#46) --- minidump/minidump_file_writer.cc | 4 +- minidump/minidump_stacktrace_writer.cc | 56 +++++++++---- minidump/minidump_stacktrace_writer.h | 4 +- snapshot/CMakeLists.txt | 2 +- snapshot/win/process_reader_win.cc | 104 ++++++++++++++++++++++--- snapshot/win/process_reader_win.h | 3 + snapshot/win/thread_snapshot_win.cc | 8 +- 7 files changed, 145 insertions(+), 36 deletions(-) diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 8cd23f241f..deb2c86f78 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -105,8 +105,8 @@ void MinidumpFileWriter::InitializeFromSnapshot( DCHECK(add_stream_result); auto stacktrace_list = std::make_unique(); - stacktrace_list->InitializeFromSnapshot(process_snapshot->Threads(), - thread_id_map); + stacktrace_list->InitializeFromSnapshot( + process_snapshot->Threads(), thread_id_map, exception_snapshot); add_stream_result = AddStream(std::move(stacktrace_list)); DCHECK(add_stream_result); diff --git a/minidump/minidump_stacktrace_writer.cc b/minidump/minidump_stacktrace_writer.cc index cc1bb70eb6..74724ca773 100644 --- a/minidump/minidump_stacktrace_writer.cc +++ b/minidump/minidump_stacktrace_writer.cc @@ -7,6 +7,7 @@ #include #include "base/logging.h" +#include "snapshot/exception_snapshot.h" #include "snapshot/thread_snapshot.h" #include "util/file/file_writer.h" @@ -32,7 +33,8 @@ MinidumpStacktraceListWriter::~MinidumpStacktraceListWriter() {} void MinidumpStacktraceListWriter::InitializeFromSnapshot( const std::vector& thread_snapshots, - const MinidumpThreadIDMap& thread_id_map) { + const MinidumpThreadIDMap& thread_id_map, + const ExceptionSnapshot* exception_snapshot) { DCHECK_EQ(state(), kStateMutable); DCHECK(threads_.empty()); @@ -49,6 +51,20 @@ void MinidumpStacktraceListWriter::InitializeFromSnapshot( std::vector frames = thread_snapshot->StackTrace(); + // filter out the stack frames that are *above* the exception addr, as those + // are related to exception handling, and not really useful. + if (exception_snapshot && + thread_snapshot->ThreadID() == exception_snapshot->ThreadID()) { + auto it = begin(frames); + for (; it != end(frames); it++) + if (it->InstructionAddr() == exception_snapshot->ExceptionAddress()) { + break; + } + if (it < end(frames)) { + frames.erase(begin(frames), it); + } + } + for (auto frame_snapshot : frames) { internal::RawFrame frame; frame.instruction_addr = frame_snapshot.InstructionAddr(); @@ -110,32 +126,38 @@ bool MinidumpStacktraceListWriter::WriteObject( iov.iov_base = &padding; iov.iov_len = align_to_8(iov.iov_len); if (iov.iov_len > 0) { - iovecs.push_back(iov); + iovecs.push_back(iov); } - iov.iov_base = &threads_.front(); - iov.iov_len = threads_.size() * sizeof(internal::RawThread); - iovecs.push_back(iov); + if (!threads_.empty()) { + iov.iov_base = &threads_.front(); + iov.iov_len = threads_.size() * sizeof(internal::RawThread); + iovecs.push_back(iov); - iov.iov_base = &padding; - iov.iov_len = align_to_8(iov.iov_len); - if (iov.iov_len > 0) { + iov.iov_base = &padding; + iov.iov_len = align_to_8(iov.iov_len); + if (iov.iov_len > 0) { iovecs.push_back(iov); + } } - iov.iov_base = &frames_.front(); - iov.iov_len = frames_.size() * sizeof(internal::RawFrame); - iovecs.push_back(iov); + if (!frames_.empty()) { + iov.iov_base = &frames_.front(); + iov.iov_len = frames_.size() * sizeof(internal::RawFrame); + iovecs.push_back(iov); - iov.iov_base = &padding; - iov.iov_len = align_to_8(iov.iov_len); - if (iov.iov_len > 0) { + iov.iov_base = &padding; + iov.iov_len = align_to_8(iov.iov_len); + if (iov.iov_len > 0) { iovecs.push_back(iov); + } } - iov.iov_base = &symbol_bytes_.front(); - iov.iov_len = symbol_bytes_.size(); - iovecs.push_back(iov); + if (!symbol_bytes_.empty()) { + iov.iov_base = &symbol_bytes_.front(); + iov.iov_len = symbol_bytes_.size(); + iovecs.push_back(iov); + } return file_writer->WriteIoVec(&iovecs); } diff --git a/minidump/minidump_stacktrace_writer.h b/minidump/minidump_stacktrace_writer.h index e1a4963ca5..cddea4e7db 100644 --- a/minidump/minidump_stacktrace_writer.h +++ b/minidump/minidump_stacktrace_writer.h @@ -40,6 +40,7 @@ struct RawFrame { } // namespace internal class ThreadSnapshot; +class ExceptionSnapshot; //! \brief The writer for our custom client-side stacktraces stream in a //! minidump file. @@ -57,7 +58,8 @@ class MinidumpStacktraceListWriter final //! identified by \a thread_snapshots. void InitializeFromSnapshot( const std::vector& thread_snapshots, - const MinidumpThreadIDMap& thread_id_map); + const MinidumpThreadIDMap& thread_id_map, + const ExceptionSnapshot* exception_snapshot); protected: // MinidumpWritable: diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 10679a1135..73b8f004b5 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -202,7 +202,7 @@ target_link_libraries(crashpad_snapshot ) if(WIN32) - target_link_libraries(crashpad_snapshot PRIVATE powrprof) + target_link_libraries(crashpad_snapshot PRIVATE powrprof dbghelp) if(MSVC) target_compile_options(crashpad_snapshot PRIVATE "/wd4201") endif() diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index e3784caefc..d88f393598 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -14,6 +14,7 @@ #include "snapshot/win/process_reader_win.h" +#include #include #include @@ -125,25 +126,102 @@ HANDLE OpenThread( return handle; } +void DoStackWalk(ProcessReaderWin::Thread* thread, + HANDLE process, + HANDLE thread_handle, + bool is_64_reading_32) { + if (is_64_reading_32) { + // TODO: we dont support it right away, maybe in the future + return; + } + + STACKFRAME64 stack_frame; + memset(&stack_frame, 0, sizeof(stack_frame)); + + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Mode = AddrModeFlat; + + int machine_type = IMAGE_FILE_MACHINE_I386; + LPVOID ctx = NULL; +#if defined(ARCH_CPU_X86) + const CONTEXT* ctx_ = &thread->context.native; + stack_frame.AddrPC.Offset = ctx_->Eip; + stack_frame.AddrFrame.Offset = ctx_->Ebp; + stack_frame.AddrStack.Offset = ctx_->Esp; + ctx = (LPVOID)ctx_; +#elif defined(ARCH_CPU_X86_64) + // if (!is_64_reading_32) { + machine_type = IMAGE_FILE_MACHINE_AMD64; + + const CONTEXT* ctx_ = &thread->context.native; + stack_frame.AddrPC.Offset = ctx_->Rip; + stack_frame.AddrFrame.Offset = ctx_->Rbp; + stack_frame.AddrStack.Offset = ctx_->Rsp; + ctx = (LPVOID)ctx_; + // } else { + // const WOW64_CONTEXT* ctx_ = &thread->context.wow64; + // stack_frame.AddrPC.Offset = ctx_->Eip; + // stack_frame.AddrFrame.Offset = ctx_->Ebp; + // stack_frame.AddrStack.Offset = ctx_->Esp; + // ctx = (LPVOID)ctx_; + // } + +// TODO: we dont support this right away, maybe in the future +//#elif defined(ARCH_CPU_ARM64) +// machine_type = IMAGE_FILE_MACHINE_ARM64; +#else +#error Unsupported Windows Arch +#endif // ARCH_CPU_X86 + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + while (StackWalk64(machine_type, + process, + thread_handle, + &stack_frame, + ctx, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + NULL)) { + uint64_t addr = stack_frame.AddrPC.Offset; + std::string sym(""); + if (SymFromAddr(process, addr, 0, pSymbol)) { + sym = std::string(pSymbol->Name); + } + FrameSnapshot frame(addr, sym); + thread->frames.push_back(frame); + } +} + // It's necessary to suspend the thread to grab CONTEXT. SuspendThread has a // side-effect of returning the SuspendCount of the thread on success, so we // fill out these two pieces of semi-unrelated data in the same function. template -bool FillThreadContextAndSuspendCount(HANDLE thread_handle, +bool FillThreadContextAndSuspendCount(HANDLE process, + HANDLE thread_handle, ProcessReaderWin::Thread* thread, ProcessSuspensionState suspension_state, bool is_64_reading_32) { // Don't suspend the thread if it's this thread. This is really only for test // binaries, as we won't be walking ourselves, in general. - bool is_current_thread = thread->id == - reinterpret_cast*>( - NtCurrentTeb())->ClientId.UniqueThread; + bool is_current_thread = + thread->id == + reinterpret_cast*>(NtCurrentTeb()) + ->ClientId.UniqueThread; if (is_current_thread) { DCHECK(suspension_state == ProcessSuspensionState::kRunning); thread->suspend_count = 0; DCHECK(!is_64_reading_32); CaptureContext(&thread->context.native); + + DoStackWalk(thread, process, thread_handle, is_64_reading_32); } else { DWORD previous_suspend_count = SuspendThread(thread_handle); if (previous_suspend_count == static_cast(-1)) { @@ -183,6 +261,8 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, } } + DoStackWalk(thread, process, thread_handle, is_64_reading_32); + if (!ResumeThread(thread_handle)) { PLOG(ERROR) << "ResumeThread"; return false; @@ -203,8 +283,7 @@ ProcessReaderWin::Thread::Thread() stack_region_size(0), suspend_count(0), priority_class(0), - priority(0) { -} + priority(0) {} ProcessReaderWin::ProcessReaderWin() : process_(INVALID_HANDLE_VALUE), @@ -214,11 +293,9 @@ ProcessReaderWin::ProcessReaderWin() modules_(), suspension_state_(), initialized_threads_(false), - initialized_() { -} + initialized_() {} -ProcessReaderWin::~ProcessReaderWin() { -} +ProcessReaderWin::~ProcessReaderWin() {} bool ProcessReaderWin::Initialize(HANDLE process, ProcessSuspensionState suspension_state) { @@ -309,6 +386,10 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { if (!process_information) return; + DWORD options = SymGetOptions(); + SymSetOptions(options | SYMOPT_UNDNAME); + SymInitialize(process_, NULL, TRUE); + for (unsigned long i = 0; i < process_information->NumberOfThreads; ++i) { const process_types::SYSTEM_THREAD_INFORMATION& thread_info = process_information->Threads[i]; @@ -319,7 +400,8 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { if (!thread_handle.is_valid()) continue; - if (!FillThreadContextAndSuspendCount(thread_handle.get(), + if (!FillThreadContextAndSuspendCount(process_, + thread_handle.get(), &thread, suspension_state_, is_64_reading_32)) { diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index a4e32aaf83..92f54a1441 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -22,6 +22,7 @@ #include "base/macros.h" #include "build/build_config.h" +#include "snapshot/thread_snapshot.h" #include "util/misc/initialization_state_dcheck.h" #include "util/process/process_memory_win.h" #include "util/win/address_types.h" @@ -60,6 +61,8 @@ class ProcessReaderWin { uint32_t suspend_count; uint32_t priority_class; uint32_t priority; + + std::vector frames; }; ProcessReaderWin(); diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index c3894a78b1..e2bdf7e3c5 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -32,11 +32,9 @@ ThreadSnapshotWin::ThreadSnapshotWin() stack_(), teb_(), thread_(), - initialized_() { -} + initialized_() {} -ThreadSnapshotWin::~ThreadSnapshotWin() { -} +ThreadSnapshotWin::~ThreadSnapshotWin() {} bool ThreadSnapshotWin::Initialize( ProcessReaderWin* process_reader, @@ -86,6 +84,8 @@ bool ThreadSnapshotWin::Initialize( #error Unsupported Windows Arch #endif // ARCH_CPU_X86 + frames_ = thread_.frames; + CaptureMemoryDelegateWin capture_memory_delegate( process_reader, thread_, From 2743206d0a52cf11730a14ca139113c679e24edd Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 11 Oct 2021 14:12:04 +0200 Subject: [PATCH 064/478] feat: Make client-side stack traces opt-in (NATIVE-262) (#48) --- CMakeLists.txt | 1 + minidump/CMakeLists.txt | 10 ++++++++-- minidump/minidump_file_writer.cc | 4 ++++ snapshot/CMakeLists.txt | 9 ++++++++- snapshot/thread_snapshot.h | 19 ++++++++++++------- snapshot/win/process_reader_win.cc | 14 ++++++++++++++ snapshot/win/process_reader_win.h | 2 ++ snapshot/win/thread_snapshot_win.cc | 2 ++ 8 files changed, 51 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index abb06971a6..7d7a479540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ endif() option(CRASHPAD_ENABLE_INSTALL "Enable crashpad installation" "${CRASHPAD_MAIN_PROJECT}") option(CRASHPAD_ENABLE_INSTALL_DEV "Enable crashpad development installation" "${CRASHPAD_MAIN_PROJECT}") +option(CRASHPAD_ENABLE_STACKTRACE "Enable client-side stack trace recording" OFF) if(MSVC) set(CRASHPAD_ZLIB_SYSTEM_DEFAULT OFF) diff --git a/minidump/CMakeLists.txt b/minidump/CMakeLists.txt index e0b8f9a04e..b964add2a7 100644 --- a/minidump/CMakeLists.txt +++ b/minidump/CMakeLists.txt @@ -30,8 +30,6 @@ add_library(crashpad_minidump STATIC minidump_rva_list_writer.h minidump_simple_string_dictionary_writer.cc minidump_simple_string_dictionary_writer.h - minidump_stacktrace_writer.cc - minidump_stacktrace_writer.h minidump_stream_writer.cc minidump_stream_writer.h minidump_string_writer.cc @@ -64,6 +62,14 @@ target_link_libraries(crashpad_minidump mini_chromium ) +if(CRASHPAD_ENABLE_STACKTRACE) + target_sources(crashpad_minidump PRIVATE + minidump_stacktrace_writer.cc + minidump_stacktrace_writer.h + ) + target_compile_definitions(crashpad_minidump PRIVATE CLIENT_STACKTRACES_ENABLED) +endif() + if(MSVC) target_compile_options(crashpad_minidump PRIVATE "/wd4201" "/wd4324") endif() diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index deb2c86f78..99ee2da06e 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -24,7 +24,9 @@ #include "minidump/minidump_memory_writer.h" #include "minidump/minidump_misc_info_writer.h" #include "minidump/minidump_module_writer.h" +#ifdef CLIENT_STACKTRACES_ENABLED #include "minidump/minidump_stacktrace_writer.h" +#endif #include "minidump/minidump_system_info_writer.h" #include "minidump/minidump_thread_id_map.h" #include "minidump/minidump_thread_writer.h" @@ -104,11 +106,13 @@ void MinidumpFileWriter::InitializeFromSnapshot( add_stream_result = AddStream(std::move(module_list)); DCHECK(add_stream_result); +#ifdef CLIENT_STACKTRACES_ENABLED auto stacktrace_list = std::make_unique(); stacktrace_list->InitializeFromSnapshot( process_snapshot->Threads(), thread_id_map, exception_snapshot); add_stream_result = AddStream(std::move(stacktrace_list)); DCHECK(add_stream_result); +#endif auto unloaded_modules = process_snapshot->UnloadedModules(); if (!unloaded_modules.empty()) { diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 73b8f004b5..c684793993 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -201,8 +201,15 @@ target_link_libraries(crashpad_snapshot mini_chromium ) +if(CRASHPAD_ENABLE_STACKTRACE) + target_compile_definitions(crashpad_snapshot PRIVATE CLIENT_STACKTRACES_ENABLED) +endif() + if(WIN32) - target_link_libraries(crashpad_snapshot PRIVATE powrprof dbghelp) + target_link_libraries(crashpad_snapshot PRIVATE powrprof) + if(CRASHPAD_ENABLE_STACKTRACE) + target_link_libraries(crashpad_snapshot PRIVATE dbghelp) + endif() if(MSVC) target_compile_options(crashpad_snapshot PRIVATE "/wd4201") endif() diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 0251fbfca6..08604a8836 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -17,14 +17,17 @@ #include -#include +#ifdef CLIENT_STACKTRACES_ENABLED #include +#endif +#include namespace crashpad { struct CPUContext; class MemorySnapshot; +#ifdef CLIENT_STACKTRACES_ENABLED class FrameSnapshot { public: FrameSnapshot(uint64_t instruction_addr, std::string symbol) @@ -37,12 +40,15 @@ class FrameSnapshot { uint64_t instruction_addr_; std::string symbol_; }; +#endif //! \brief An abstract interface to a snapshot representing a thread //! (lightweight process) present in a snapshot process. class ThreadSnapshot { public: +#ifdef CLIENT_STACKTRACES_ENABLED ThreadSnapshot() : frames_() {} +#endif virtual ~ThreadSnapshot() {} @@ -90,13 +96,12 @@ class ThreadSnapshot { //! were obtained from. virtual std::vector ExtraMemory() const = 0; - const std::vector& StackTrace() const { - return frames_; - } - - protected: - std::vector frames_; +#ifdef CLIENT_STACKTRACES_ENABLED + const std::vector& StackTrace() const { return frames_; } + protected: + std::vector frames_; +#endif }; } // namespace crashpad diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index d88f393598..ff4a23615b 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -14,7 +14,9 @@ #include "snapshot/win/process_reader_win.h" +#ifdef CLIENT_STACKTRACES_ENABLED #include +#endif #include #include @@ -126,6 +128,7 @@ HANDLE OpenThread( return handle; } +#ifdef CLIENT_STACKTRACES_ENABLED void DoStackWalk(ProcessReaderWin::Thread* thread, HANDLE process, HANDLE thread_handle, @@ -198,6 +201,7 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, thread->frames.push_back(frame); } } +#endif // It's necessary to suspend the thread to grab CONTEXT. SuspendThread has a // side-effect of returning the SuspendCount of the thread on success, so we @@ -208,6 +212,10 @@ bool FillThreadContextAndSuspendCount(HANDLE process, ProcessReaderWin::Thread* thread, ProcessSuspensionState suspension_state, bool is_64_reading_32) { +#ifndef CLIENT_STACKTRACES_ENABLED + (void)process; +#endif + // Don't suspend the thread if it's this thread. This is really only for test // binaries, as we won't be walking ourselves, in general. bool is_current_thread = @@ -221,7 +229,9 @@ bool FillThreadContextAndSuspendCount(HANDLE process, DCHECK(!is_64_reading_32); CaptureContext(&thread->context.native); +#ifdef CLIENT_STACKTRACES_ENABLED DoStackWalk(thread, process, thread_handle, is_64_reading_32); +#endif } else { DWORD previous_suspend_count = SuspendThread(thread_handle); if (previous_suspend_count == static_cast(-1)) { @@ -261,7 +271,9 @@ bool FillThreadContextAndSuspendCount(HANDLE process, } } +#ifdef CLIENT_STACKTRACES_ENABLED DoStackWalk(thread, process, thread_handle, is_64_reading_32); +#endif if (!ResumeThread(thread_handle)) { PLOG(ERROR) << "ResumeThread"; @@ -386,9 +398,11 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { if (!process_information) return; +#ifdef CLIENT_STACKTRACES_ENABLED DWORD options = SymGetOptions(); SymSetOptions(options | SYMOPT_UNDNAME); SymInitialize(process_, NULL, TRUE); +#endif for (unsigned long i = 0; i < process_information->NumberOfThreads; ++i) { const process_types::SYSTEM_THREAD_INFORMATION& thread_info = diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index 92f54a1441..c033cf7687 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -62,7 +62,9 @@ class ProcessReaderWin { uint32_t priority_class; uint32_t priority; +#ifdef CLIENT_STACKTRACES_ENABLED std::vector frames; +#endif }; ProcessReaderWin(); diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index e2bdf7e3c5..b891b05b94 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -84,7 +84,9 @@ bool ThreadSnapshotWin::Initialize( #error Unsupported Windows Arch #endif // ARCH_CPU_X86 +#ifdef CLIENT_STACKTRACES_ENABLED frames_ = thread_.frames; +#endif CaptureMemoryDelegateWin capture_memory_delegate( process_reader, From 94945e7724000ff915c8acaf1fc355f413ce3f36 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 18 Oct 2021 12:37:30 +0200 Subject: [PATCH 065/478] meta: Build client-side stack walking code in CI (#51) --- .github/workflows/build.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5211b0776..ce12943427 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,10 +17,22 @@ jobs: - uses: actions/checkout@v2 with: submodules: "recursive" - - uses: lukka/run-cmake@v2 - with: - cmakeListsOrSettingsJson: "CMakeListsTxtAdvanced" - buildWithCMakeArgs: "--parallel" + + - name: Installing Linux Dependencies + if: ${{ runner.os == 'Linux' }} + run: | + sudo apt update + sudo apt install zlib1g-dev libcurl4-openssl-dev libssl-dev libunwind-dev + + - name: Build crashpad + run: | + cmake -B cmake-build + cmake --build cmake-build --parallel + + - name: Build crashpad with client-side stack traces + run: | + cmake -B cmake-build-stacks -D CRASHPAD_ENABLE_STACKTRACE=ON + cmake --build cmake-build-stacks --parallel build-ios: runs-on: macos-latest From 4be14116a305d9283c9019fb3fe6540a902fc860 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 18 Oct 2021 12:40:42 +0200 Subject: [PATCH 066/478] meta: Vendor libunwind (#50) This just copied the source of `libunwind` from llvm-project, without any changes. --- libunwind/.clang-format | 2 + libunwind/CMakeLists.txt | 373 ++ libunwind/LICENSE.TXT | 311 ++ .../cmake/Modules/HandleCompilerRT.cmake | 64 + .../cmake/Modules/HandleLibunwindFlags.cmake | 283 ++ libunwind/cmake/config-ix.cmake | 105 + libunwind/docs/BuildingLibunwind.rst | 168 + libunwind/docs/CMakeLists.txt | 7 + libunwind/docs/README.txt | 13 + libunwind/docs/conf.py | 252 + libunwind/docs/index.rst | 104 + libunwind/include/__libunwind_config.h | 176 + libunwind/include/libunwind.h | 1176 +++++ .../include/mach-o/compact_unwind_encoding.h | 477 ++ libunwind/include/unwind.h | 207 + libunwind/include/unwind_arm_ehabi.h | 169 + libunwind/include/unwind_itanium.h | 76 + libunwind/src/AddressSpace.hpp | 630 +++ libunwind/src/CMakeLists.txt | 211 + libunwind/src/CompactUnwinder.hpp | 697 +++ libunwind/src/DwarfInstructions.hpp | 838 +++ libunwind/src/DwarfParser.hpp | 813 +++ libunwind/src/EHHeaderParser.hpp | 169 + libunwind/src/FrameHeaderCache.hpp | 149 + libunwind/src/RWMutex.hpp | 114 + libunwind/src/Registers.hpp | 4509 +++++++++++++++++ libunwind/src/Unwind-EHABI.cpp | 1141 +++++ libunwind/src/Unwind-EHABI.h | 50 + libunwind/src/Unwind-seh.cpp | 491 ++ libunwind/src/Unwind-sjlj.c | 528 ++ libunwind/src/UnwindCursor.hpp | 2146 ++++++++ libunwind/src/UnwindLevel1-gcc-ext.c | 317 ++ libunwind/src/UnwindLevel1.c | 561 ++ libunwind/src/UnwindRegistersRestore.S | 1167 +++++ libunwind/src/UnwindRegistersSave.S | 1117 ++++ libunwind/src/Unwind_AppleExtras.cpp | 113 + libunwind/src/assembly.h | 230 + libunwind/src/cet_unwind.h | 41 + libunwind/src/config.h | 241 + libunwind/src/dwarf2.h | 239 + libunwind/src/libunwind.cpp | 341 ++ libunwind/src/libunwind_ext.h | 65 + libunwind/test/CMakeLists.txt | 61 + libunwind/test/alignment.compile.pass.cpp | 24 + libunwind/test/floatregister.pass.cpp | 51 + libunwind/test/forceunwind.pass.cpp | 74 + libunwind/test/frameheadercache_test.pass.cpp | 78 + libunwind/test/libunwind/__init__.py | 0 libunwind/test/libunwind/test/__init__.py | 0 libunwind/test/libunwind/test/config.py | 71 + libunwind/test/libunwind_01.pass.cpp | 147 + libunwind/test/libunwind_02.pass.cpp | 45 + libunwind/test/lit.cfg.py | 10 + libunwind/test/lit.site.cfg.in | 58 + libunwind/test/remember_state_leak.pass.sh.s | 65 + libunwind/test/signal_frame.pass.cpp | 40 + libunwind/test/signal_unwind.pass.cpp | 52 + libunwind/test/unw_getcontext.pass.cpp | 12 + libunwind/test/unwind_leaffunction.pass.cpp | 57 + 59 files changed, 21726 insertions(+) create mode 100644 libunwind/.clang-format create mode 100644 libunwind/CMakeLists.txt create mode 100644 libunwind/LICENSE.TXT create mode 100644 libunwind/cmake/Modules/HandleCompilerRT.cmake create mode 100644 libunwind/cmake/Modules/HandleLibunwindFlags.cmake create mode 100644 libunwind/cmake/config-ix.cmake create mode 100644 libunwind/docs/BuildingLibunwind.rst create mode 100644 libunwind/docs/CMakeLists.txt create mode 100644 libunwind/docs/README.txt create mode 100644 libunwind/docs/conf.py create mode 100644 libunwind/docs/index.rst create mode 100644 libunwind/include/__libunwind_config.h create mode 100644 libunwind/include/libunwind.h create mode 100644 libunwind/include/mach-o/compact_unwind_encoding.h create mode 100644 libunwind/include/unwind.h create mode 100644 libunwind/include/unwind_arm_ehabi.h create mode 100644 libunwind/include/unwind_itanium.h create mode 100644 libunwind/src/AddressSpace.hpp create mode 100644 libunwind/src/CMakeLists.txt create mode 100644 libunwind/src/CompactUnwinder.hpp create mode 100644 libunwind/src/DwarfInstructions.hpp create mode 100644 libunwind/src/DwarfParser.hpp create mode 100644 libunwind/src/EHHeaderParser.hpp create mode 100644 libunwind/src/FrameHeaderCache.hpp create mode 100644 libunwind/src/RWMutex.hpp create mode 100644 libunwind/src/Registers.hpp create mode 100644 libunwind/src/Unwind-EHABI.cpp create mode 100644 libunwind/src/Unwind-EHABI.h create mode 100644 libunwind/src/Unwind-seh.cpp create mode 100644 libunwind/src/Unwind-sjlj.c create mode 100644 libunwind/src/UnwindCursor.hpp create mode 100644 libunwind/src/UnwindLevel1-gcc-ext.c create mode 100644 libunwind/src/UnwindLevel1.c create mode 100644 libunwind/src/UnwindRegistersRestore.S create mode 100644 libunwind/src/UnwindRegistersSave.S create mode 100644 libunwind/src/Unwind_AppleExtras.cpp create mode 100644 libunwind/src/assembly.h create mode 100644 libunwind/src/cet_unwind.h create mode 100644 libunwind/src/config.h create mode 100644 libunwind/src/dwarf2.h create mode 100644 libunwind/src/libunwind.cpp create mode 100644 libunwind/src/libunwind_ext.h create mode 100644 libunwind/test/CMakeLists.txt create mode 100644 libunwind/test/alignment.compile.pass.cpp create mode 100644 libunwind/test/floatregister.pass.cpp create mode 100644 libunwind/test/forceunwind.pass.cpp create mode 100644 libunwind/test/frameheadercache_test.pass.cpp create mode 100644 libunwind/test/libunwind/__init__.py create mode 100644 libunwind/test/libunwind/test/__init__.py create mode 100644 libunwind/test/libunwind/test/config.py create mode 100644 libunwind/test/libunwind_01.pass.cpp create mode 100644 libunwind/test/libunwind_02.pass.cpp create mode 100644 libunwind/test/lit.cfg.py create mode 100644 libunwind/test/lit.site.cfg.in create mode 100644 libunwind/test/remember_state_leak.pass.sh.s create mode 100644 libunwind/test/signal_frame.pass.cpp create mode 100644 libunwind/test/signal_unwind.pass.cpp create mode 100644 libunwind/test/unw_getcontext.pass.cpp create mode 100644 libunwind/test/unwind_leaffunction.pass.cpp diff --git a/libunwind/.clang-format b/libunwind/.clang-format new file mode 100644 index 0000000000..5bead5f39d --- /dev/null +++ b/libunwind/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM + diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt new file mode 100644 index 0000000000..9b55195b83 --- /dev/null +++ b/libunwind/CMakeLists.txt @@ -0,0 +1,373 @@ +if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libcxx") + message(FATAL_ERROR "libunwind requires being built in a monorepo layout with libcxx available") +endif() + +#=============================================================================== +# Setup Project +#=============================================================================== + +cmake_minimum_required(VERSION 3.13.4) + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + ${CMAKE_MODULE_PATH} + ) + +set(LIBUNWIND_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(LIBUNWIND_LIBCXX_PATH "${CMAKE_CURRENT_LIST_DIR}/../libcxx" CACHE PATH + "Specify path to libc++ source.") + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_BUILD) + project(libunwind LANGUAGES C CXX ASM) + + set(PACKAGE_NAME libunwind) + set(PACKAGE_VERSION 14.0.0git) + set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") + set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") + + # Add the CMake module path of libcxx so we can reuse HandleOutOfTreeLLVM.cmake + set(LIBUNWIND_LIBCXX_CMAKE_PATH "${LIBUNWIND_LIBCXX_PATH}/cmake/Modules") + list(APPEND CMAKE_MODULE_PATH "${LIBUNWIND_LIBCXX_CMAKE_PATH}") + + # In a standalone build, we don't have llvm to automatically generate the + # llvm-lit script for us. So we need to provide an explicit directory that + # the configurator should write the script into. + set(LIBUNWIND_STANDALONE_BUILD 1) + set(LLVM_LIT_OUTPUT_DIR "${LIBUNWIND_BINARY_DIR}/bin") + + # Find the LLVM sources and simulate LLVM CMake options. + include(HandleOutOfTreeLLVM) +else() + set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py") +endif() + +#=============================================================================== +# Setup CMake Options +#=============================================================================== +include(CMakeDependentOption) +include(HandleCompilerRT) + +# Define options. +option(LIBUNWIND_BUILD_32_BITS "Build 32 bit libunwind" ${LLVM_BUILD_32_BITS}) +option(LIBUNWIND_ENABLE_CET "Build libunwind with CET enabled." OFF) +option(LIBUNWIND_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) +option(LIBUNWIND_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) +option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) +option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON) +option(LIBUNWIND_ENABLE_STATIC "Build libunwind as a static library." ON) +option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF) +option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF) +option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON) +option(LIBUNWIND_WEAK_PTHREAD_LIB "Use weak references to refer to pthread functions." OFF) +option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF) +option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS}) +option(LIBUNWIND_INCLUDE_TESTS "Build the libunwind tests." ${LLVM_INCLUDE_TESTS}) +option(LIBUNWIND_IS_BAREMETAL "Build libunwind for baremetal targets." OFF) +option(LIBUNWIND_USE_FRAME_HEADER_CACHE "Cache frame headers for unwinding. Requires locking dl_iterate_phdr." OFF) +option(LIBUNWIND_REMEMBER_HEAP_ALLOC "Use heap instead of the stack for .cfi_remember_state." OFF) + +set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") +option(LIBUNWIND_INSTALL_LIBRARY "Install the libunwind library." ON) +cmake_dependent_option(LIBUNWIND_INSTALL_STATIC_LIBRARY + "Install the static libunwind library." ON + "LIBUNWIND_ENABLE_STATIC;LIBUNWIND_INSTALL_LIBRARY" OFF) +cmake_dependent_option(LIBUNWIND_INSTALL_SHARED_LIBRARY + "Install the shared libunwind library." ON + "LIBUNWIND_ENABLE_SHARED;LIBUNWIND_INSTALL_LIBRARY" OFF) +set(LIBUNWIND_TARGET_TRIPLE "${LLVM_DEFAULT_TARGET_TRIPLE}" CACHE STRING "Target triple for cross compiling.") +set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") +set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") +set(LIBUNWIND_TEST_LINKER_FLAGS "" CACHE STRING + "Additional linker flags for test programs.") +set(LIBUNWIND_TEST_COMPILER_FLAGS "" CACHE STRING + "Additional compiler flags for test programs.") +set(LIBUNWIND_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/lit.site.cfg.in" CACHE STRING + "The path to the Lit testing configuration to use when running the tests. + If a relative path is provided, it is assumed to be relative to '/libcxx/test/configs'.") +if (NOT IS_ABSOLUTE "${LIBUNWIND_TEST_CONFIG}") + set(LIBUNWIND_TEST_CONFIG "${LIBUNWIND_LIBCXX_PATH}/test/configs/${LIBUNWIND_TEST_CONFIG}") +endif() +set(LIBUNWIND_TEST_PARAMS "" CACHE STRING + "A list of parameters to run the Lit test suite with.") + +if (NOT LIBUNWIND_ENABLE_SHARED AND NOT LIBUNWIND_ENABLE_STATIC) + message(FATAL_ERROR "libunwind must be built as either a shared or static library.") +endif() + +if (LIBUNWIND_ENABLE_CET AND MSVC) + message(FATAL_ERROR "libunwind CET support is not available for MSVC!") +endif() + +# Check that we can build with 32 bits if requested. +if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32) + if (LIBUNWIND_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM + message(STATUS "Building 32 bits executables and libraries.") + endif() +elseif(LIBUNWIND_BUILD_32_BITS) + message(FATAL_ERROR "LIBUNWIND_BUILD_32_BITS=ON is not supported on this platform.") +endif() + +option(LIBUNWIND_HIDE_SYMBOLS + "Do not export any symbols from the static library." OFF) + +#=============================================================================== +# Configure System +#=============================================================================== + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + ${CMAKE_MODULE_PATH}) + +if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) + set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE PATH + "Path where built libunwind libraries should be installed.") + set(LIBUNWIND_INSTALL_RUNTIME_DIR bin CACHE PATH + "Path where built libunwind runtime libraries should be installed.") + if(LIBCXX_LIBDIR_SUBDIR) + string(APPEND LIBUNWIND_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR}) + string(APPEND LIBUNWIND_INSTALL_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR}) + endif() +elseif(LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX} CACHE PATH + "Path where built libunwind libraries should be installed.") + set(LIBUNWIND_INSTALL_RUNTIME_DIR bin CACHE PATH + "Path where built libunwind runtime libraries should be installed.") +else() + set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX}) + set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX} CACHE PATH + "Path where built libunwind libraries should be installed.") + set(LIBUNWIND_INSTALL_RUNTIME_DIR bin CACHE PATH + "Path where built libunwind runtime libraries should be installed.") +endif() + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR}) + +set(LIBUNWIND_C_FLAGS "") +set(LIBUNWIND_CXX_FLAGS "") +set(LIBUNWIND_COMPILE_FLAGS "") +set(LIBUNWIND_LINK_FLAGS "") + +# Include macros for adding and removing libunwind flags. +include(HandleLibunwindFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== + +# Get required flags. +add_target_flags_if(LIBUNWIND_BUILD_32_BITS "-m32") + +if(LIBUNWIND_TARGET_TRIPLE) + add_target_flags_if_supported("--target=${LIBUNWIND_TARGET_TRIPLE}") +elseif(CMAKE_CXX_COMPILER_TARGET) + set(LIBUNWIND_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}") +endif() +if(LIBUNWIND_GCC_TOOLCHAIN) + add_target_flags_if_supported("--gcc-toolchain=${LIBUNWIND_GCC_TOOLCHAIN}") +elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) + set(LIBUNWIND_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") +endif() +if(LIBUNWIND_SYSROOT) + add_target_flags_if_supported("--sysroot=${LIBUNWIND_SYSROOT}") +elseif(CMAKE_SYSROOT) + set(LIBUNWIND_SYSROOT "${CMAKE_SYSROOT}") +endif() + +# Configure compiler. +include(config-ix) + +if (LIBUNWIND_USE_COMPILER_RT AND NOT LIBUNWIND_HAS_NODEFAULTLIBS_FLAG) + list(APPEND LIBUNWIND_LINK_FLAGS "-rtlib=compiler-rt") +endif() + +add_compile_flags_if_supported(-Werror=return-type) + +if (LIBUNWIND_ENABLE_CET) + add_compile_flags_if_supported(-fcf-protection=full) + add_compile_flags_if_supported(-mshstk) + if (NOT LIBUNWIND_SUPPORTS_FCF_PROTECTION_EQ_FULL_FLAG) + message(SEND_ERROR "Compiler doesn't support CET -fcf-protection option!") + endif() + if (NOT LIBUNWIND_SUPPORTS_MSHSTK_FLAG) + message(SEND_ERROR "Compiler doesn't support CET -mshstk option!") + endif() +endif() + +# Get warning flags +add_compile_flags_if_supported(-W) +add_compile_flags_if_supported(-Wall) +add_compile_flags_if_supported(-Wchar-subscripts) +add_compile_flags_if_supported(-Wconversion) +add_compile_flags_if_supported(-Wmismatched-tags) +add_compile_flags_if_supported(-Wmissing-braces) +add_compile_flags_if_supported(-Wnewline-eof) +add_compile_flags_if_supported(-Wno-unused-function) +add_compile_flags_if_supported(-Wshadow) +add_compile_flags_if_supported(-Wshorten-64-to-32) +add_compile_flags_if_supported(-Wsign-compare) +add_compile_flags_if_supported(-Wsign-conversion) +add_compile_flags_if_supported(-Wstrict-aliasing=2) +add_compile_flags_if_supported(-Wstrict-overflow=4) +add_compile_flags_if_supported(-Wunused-parameter) +add_compile_flags_if_supported(-Wunused-variable) +add_compile_flags_if_supported(-Wwrite-strings) +add_compile_flags_if_supported(-Wundef) + +add_compile_flags_if_supported(-Wno-suggest-override) + +if (WIN32) + # The headers lack matching dllexport attributes (_LIBUNWIND_EXPORT); + # silence the warning instead of cluttering the headers (which aren't + # necessarily the ones that the callers will use anyway) with the + # attributes. + add_compile_flags_if_supported(-Wno-dll-attribute-on-redeclaration) +endif() + +if (LIBUNWIND_ENABLE_WERROR) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) +else() + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) +endif() + +if (LIBUNWIND_ENABLE_PEDANTIC) + add_compile_flags_if_supported(-pedantic) +endif() + +# Get feature flags. +# Exceptions +# Catches C++ exceptions only and tells the compiler to assume that extern C +# functions never throw a C++ exception. +add_cxx_compile_flags_if_supported(-fstrict-aliasing) +add_cxx_compile_flags_if_supported(-EHsc) + +# Don't run the linker in this CMake check. +# +# The reason why this was added is that when building libunwind for +# ARM Linux, we need to pass the -funwind-tables flag in order for it to +# work properly with ARM EHABI. +# +# However, when performing CMake checks, adding this flag causes the check +# to produce a false negative, because the compiler generates calls +# to __aeabi_unwind_cpp_pr0, which is defined in libunwind itself, +# which isn't built yet, so the linker complains about undefined symbols. +# +# This leads to libunwind not being built with this flag, which makes +# libunwind quite useless in this setup. +set(_previous_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +add_compile_flags_if_supported(-funwind-tables) +set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_previous_CMAKE_TRY_COMPILE_TARGET_TYPE}) + +if (LIBUNWIND_USES_ARM_EHABI AND NOT LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG) + message(SEND_ERROR "The -funwind-tables flag must be supported " + "because this target uses ARM Exception Handling ABI") +endif() + +add_cxx_compile_flags_if_supported(-fno-exceptions) +add_cxx_compile_flags_if_supported(-fno-rtti) + +# Ensure that we don't depend on C++ standard library. +if (LIBUNWIND_HAS_NOSTDINCXX_FLAG) + list(APPEND LIBUNWIND_COMPILE_FLAGS -nostdinc++) + # Remove -stdlib flags to prevent them from causing an unused flag warning. + string(REPLACE "--stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "--stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +# Assert +string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) +if (LIBUNWIND_ENABLE_ASSERTIONS) + # MSVC doesn't like _DEBUG on release builds. See PR 4379. + if (NOT MSVC) + add_compile_flags(-D_DEBUG) + endif() + + # On Release builds cmake automatically defines NDEBUG, so we + # explicitly undefine it: + if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + add_compile_flags(-UNDEBUG) + endif() +else() + if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + add_compile_flags(-DNDEBUG) + endif() +endif() + +# Cross-unwinding +if (NOT LIBUNWIND_ENABLE_CROSS_UNWINDING) + add_compile_flags(-D_LIBUNWIND_IS_NATIVE_ONLY) +endif() + +# Threading-support +if (NOT LIBUNWIND_ENABLE_THREADS) + add_compile_flags(-D_LIBUNWIND_HAS_NO_THREADS) +endif() + +# ARM WMMX register support +if (LIBUNWIND_ENABLE_ARM_WMMX) + # __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not + # define this macro for any supported target at present. Therefore, here we + # provide the option to explicitly enable support for WMMX registers in the + # unwinder. + add_compile_flags(-D__ARM_WMMX) +endif() + +if(LIBUNWIND_IS_BAREMETAL) + add_compile_definitions(_LIBUNWIND_IS_BAREMETAL) +endif() + +if(LIBUNWIND_USE_FRAME_HEADER_CACHE) + add_compile_definitions(_LIBUNWIND_USE_FRAME_HEADER_CACHE) +endif() + +if(LIBUNWIND_REMEMBER_HEAP_ALLOC) + add_compile_definitions(_LIBUNWIND_REMEMBER_HEAP_ALLOC) +endif() + +# This is the _ONLY_ place where add_definitions is called. +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +# Disable DLL annotations on Windows for static builds. +if (WIN32 AND LIBUNWIND_ENABLE_STATIC AND NOT LIBUNWIND_ENABLE_SHARED) + add_definitions(-D_LIBUNWIND_HIDE_SYMBOLS) +endif() + +if (LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) + if (LIBUNWIND_HAS_DL_LIB) + add_definitions(-D_LIBUNWIND_LINK_DL_LIB) + endif() + if (LIBUNWIND_HAS_PTHREAD_LIB) + add_definitions(-D_LIBUNWIND_LINK_PTHREAD_LIB) + endif() +endif() + +#=============================================================================== +# Setup Source Code +#=============================================================================== + +include_directories(include) + +add_subdirectory(src) + +if (LIBUNWIND_INCLUDE_DOCS) + add_subdirectory(docs) +endif() + +if (LIBUNWIND_INCLUDE_TESTS AND EXISTS ${LLVM_CMAKE_DIR}) + add_subdirectory(test) +endif() diff --git a/libunwind/LICENSE.TXT b/libunwind/LICENSE.TXT new file mode 100644 index 0000000000..1e3120621c --- /dev/null +++ b/libunwind/LICENSE.TXT @@ -0,0 +1,311 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== + +The libunwind library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/libunwind/cmake/Modules/HandleCompilerRT.cmake b/libunwind/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 0000000000..77168e5994 --- /dev/null +++ b/libunwind/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,64 @@ +function(find_compiler_rt_library name dest) + if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS) + message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) + list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") + endif() + get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) + string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}") + list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS}) + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") + message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") + set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt library") + endif() +endfunction() + +function(find_compiler_rt_dir dest) + if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS) + message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + if (APPLE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "-print-file-name=lib") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_DIR + ) + string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) + file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) + set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") + else() + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) + endif() + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}") + message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}") + set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt directory") + endif() +endfunction() diff --git a/libunwind/cmake/Modules/HandleLibunwindFlags.cmake b/libunwind/cmake/Modules/HandleLibunwindFlags.cmake new file mode 100644 index 0000000000..675071f943 --- /dev/null +++ b/libunwind/cmake/Modules/HandleLibunwindFlags.cmake @@ -0,0 +1,283 @@ +# HandleLibcxxFlags - A set of macros used to setup the flags used to compile +# and link libc++abi. These macros add flags to the following CMake variables. +# - LIBUNWIND_COMPILE_FLAGS: flags used to compile libunwind +# - LIBUNWIND_LINK_FLAGS: flags used to link libunwind +# - LIBUNWIND_LIBRARIES: libraries to link libunwind to. + +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +unset(add_flag_if_supported) + +# Mangle the name of a compiler flag into a valid CMake identifier. +# Ex: --std=c++11 -> STD_EQ_CXX11 +macro(mangle_name str output) + string(STRIP "${str}" strippedStr) + string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}") + string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}") + string(REPLACE "-" "_" strippedStr "${strippedStr}") + string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}") + string(REPLACE "+" "X" strippedStr "${strippedStr}") + string(TOUPPER "${strippedStr}" ${output}) +endmacro() + +# Remove a list of flags from all CMake variables that affect compile flags. +# This can be used to remove unwanted flags specified on the command line +# or added in other parts of LLVM's cmake configuration. +macro(remove_flags) + foreach(var ${ARGN}) + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}") + remove_definitions(${var}) + endforeach() +endmacro(remove_flags) + +macro(check_flag_supported flag) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") +endmacro() + +macro(append_flags DEST) + foreach(value ${ARGN}) + list(APPEND ${DEST} ${value}) + list(APPEND ${DEST} ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then append the specified list of flags to DEST +macro(append_flags_if condition DEST) + if (${condition}) + list(APPEND ${DEST} ${ARGN}) + endif() +endmacro() + +# Add each flag in the list specified by DEST if that flag is supported by the current compiler. +macro(append_flags_if_supported DEST) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + append_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${DEST} ${flag}) + endforeach() +endmacro() + +# Add a macro definition if condition is true. +macro(define_if condition def) + if (${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition if condition is not true. +macro(define_if_not condition def) + if (NOT ${condition}) + add_definitions(${def}) + endif() +endmacro() + +# Add a macro definition to the __config_site file if the specified condition +# is 'true'. Note that '-D${def}' is not added. Instead it is expected that +# the build include the '__config_site' header. +macro(config_define_if condition def) + if (${condition}) + set(${def} ON) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define_if_not condition def) + if (NOT ${condition}) + set(${def} ON) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) + endif() +endmacro() + +macro(config_define value def) + set(${def} ${value}) + set(LIBUNWIND_NEEDS_SITE_CONFIG ON) +endmacro() + +# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', +# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'. +macro(add_target_flags) + foreach(value ${ARGN}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}") + list(APPEND LIBUNWIND_COMPILE_FLAGS ${value}) + list(APPEND LIBUNWIND_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to +# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBUNWIND_COMPILE_FLAGS' +# and 'LIBUNWIND_LINK_FLAGS'. +macro(add_target_flags_if condition) + if (${condition}) + add_target_flags(${ARGN}) + endif() +endmacro() + +# Add all the flags supported by the compiler to all of +# 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBUNWIND_COMPILE_FLAGS' +# and 'LIBUNWIND_LINK_FLAGS'. +macro(add_target_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_target_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a specified list of flags to both 'LIBUNWIND_COMPILE_FLAGS' and +# 'LIBUNWIND_LINK_FLAGS'. +macro(add_flags) + foreach(value ${ARGN}) + list(APPEND LIBUNWIND_COMPILE_FLAGS ${value}) + list(APPEND LIBUNWIND_LINK_FLAGS ${value}) + endforeach() +endmacro() + +# If the specified 'condition' is true then add a list of flags to both +# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'. +macro(add_flags_if condition) + if (${condition}) + add_flags(${ARGN}) + endif() +endmacro() + +# Add each flag in the list to LIBUNWIND_COMPILE_FLAGS and LIBUNWIND_LINK_FLAGS +# if that flag is supported by the current compiler. +macro(add_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_COMPILE_FLAGS'. +macro(add_compile_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_COMPILE_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_COMPILE_FLAGS' +macro(add_compile_flags_if condition) + if (${condition}) + add_compile_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_COMPILE_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_compile_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_C_FLAGS'. +macro(add_c_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_C_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_C_FLAGS' +macro(add_c_flags_if condition) + if (${condition}) + add_c_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_C_FLAGS' if the +# flag is supported by the C compiler. +macro(add_c_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_c_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_c_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_CXX_FLAGS'. +macro(add_cxx_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_CXX_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_CXX_FLAGS' +macro(add_cxx_flags_if condition) + if (${condition}) + add_cxx_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_CXX_FLAGS' if the +# flag is supported by the C compiler. +macro(add_cxx_compile_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_cxx_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of flags to 'LIBUNWIND_LINK_FLAGS'. +macro(add_link_flags) + foreach(f ${ARGN}) + list(APPEND LIBUNWIND_LINK_FLAGS ${f}) + endforeach() +endmacro() + +# If 'condition' is true then add the specified list of flags to +# 'LIBUNWIND_LINK_FLAGS' +macro(add_link_flags_if condition) + if (${condition}) + add_link_flags(${ARGN}) + endif() +endmacro() + +# For each specified flag, add that flag to 'LIBUNWIND_LINK_FLAGS' if the +# flag is supported by the C++ compiler. +macro(add_link_flags_if_supported) + foreach(flag ${ARGN}) + mangle_name("${flag}" flagname) + check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG") + add_link_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag}) + endforeach() +endmacro() + +# Add a list of libraries or link flags to 'LIBUNWIND_LIBRARIES'. +macro(add_library_flags) + foreach(lib ${ARGN}) + list(APPEND LIBUNWIND_LIBRARIES ${lib}) + endforeach() +endmacro() + +# if 'condition' is true then add the specified list of libraries and flags +# to 'LIBUNWIND_LIBRARIES'. +macro(add_library_flags_if condition) + if(${condition}) + add_library_flags(${ARGN}) + endif() +endmacro() + +# Turn a comma separated CMake list into a space separated string. +macro(split_list listname) + string(REPLACE ";" " " ${listname} "${${listname}}") +endmacro() diff --git a/libunwind/cmake/config-ix.cmake b/libunwind/cmake/config-ix.cmake new file mode 100644 index 0000000000..4ca6bdd8e9 --- /dev/null +++ b/libunwind/cmake/config-ix.cmake @@ -0,0 +1,105 @@ +include(CMakePushCheckState) +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) +include(CheckLibraryExists) +include(CheckSymbolExists) +include(CheckCSourceCompiles) + +check_library_exists(c fopen "" LIBUNWIND_HAS_C_LIB) + +if (NOT LIBUNWIND_USE_COMPILER_RT) + if (ANDROID) + check_library_exists(gcc __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_LIB) + else () + check_library_exists(gcc_s __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_S_LIB) + check_library_exists(gcc __absvdi2 "" LIBUNWIND_HAS_GCC_LIB) + endif () +endif() + +# libunwind is using -nostdlib++ at the link step when available, +# otherwise -nodefaultlibs is used. We want all our checks to also +# use one of these options, otherwise we may end up with an inconsistency between +# the flags we think we require during configuration (if the checks are +# performed without one of those options) and the flags that are actually +# required during compilation (which has the -nostdlib++ or -nodefaultlibs). libc is +# required for the link to go through. We remove sanitizers from the +# configuration checks to avoid spurious link errors. + +check_c_compiler_flag(-nostdlib++ LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG) +if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++") +else() + check_c_compiler_flag(-nodefaultlibs LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG) + if (LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + endif() +endif() + +if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG OR LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG) + if (LIBUNWIND_HAS_C_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (LIBUNWIND_USE_COMPILER_RT) + find_compiler_rt_library(builtins LIBUNWIND_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBUNWIND_BUILTINS_LIBRARY}") + else () + if (LIBUNWIND_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () + if (LIBUNWIND_HAS_GCC_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc) + endif () + endif () + if (MINGW) + # Mingw64 requires quite a few "C" runtime libraries in order for basic + # programs to link successfully with -nodefaultlibs. + if (LIBUNWIND_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) + endif() + if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") + endif () + if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") + endif () +endif () + +# Check compiler pragmas +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unknown-pragmas") + check_c_source_compiles(" +#pragma comment(lib, \"c\") +int main() { return 0; } +" LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) + cmake_pop_check_state() +endif() + +# Check compiler flags +check_cxx_compiler_flag(-nostdinc++ LIBUNWIND_HAS_NOSTDINCXX_FLAG) + +# Check symbols +check_symbol_exists(__arm__ "" LIBUNWIND_TARGET_ARM) +check_symbol_exists(__USING_SJLJ_EXCEPTIONS__ "" LIBUNWIND_USES_SJLJ_EXCEPTIONS) +check_symbol_exists(__ARM_DWARF_EH__ "" LIBUNWIND_USES_DWARF_EH) + +if(LIBUNWIND_TARGET_ARM AND NOT LIBUNWIND_USES_SJLJ_EXCEPTIONS AND NOT LIBUNWIND_USES_DWARF_EH) + # This condition is copied from __libunwind_config.h + set(LIBUNWIND_USES_ARM_EHABI ON) +endif() + +# Check libraries +if(FUCHSIA) + set(LIBUNWIND_HAS_DL_LIB NO) + set(LIBUNWIND_HAS_PTHREAD_LIB NO) +else() + check_library_exists(dl dladdr "" LIBUNWIND_HAS_DL_LIB) + check_library_exists(pthread pthread_once "" LIBUNWIND_HAS_PTHREAD_LIB) +endif() diff --git a/libunwind/docs/BuildingLibunwind.rst b/libunwind/docs/BuildingLibunwind.rst new file mode 100644 index 0000000000..9b11042a65 --- /dev/null +++ b/libunwind/docs/BuildingLibunwind.rst @@ -0,0 +1,168 @@ +.. _BuildingLibunwind: + +================== +Building libunwind +================== + +.. contents:: + :local: + +.. _build instructions: + +Getting Started +=============== + +On Mac OS, the easiest way to get this library is to link with -lSystem. +However if you want to build tip-of-trunk from here (getting the bleeding +edge), read on. + +The basic steps needed to build libc++ are: + +#. Checkout LLVM, libunwind, and related projects: + + * ``cd where-you-want-llvm-to-live`` + * ``git clone https://github.com/llvm/llvm-project.git`` + +#. Configure and build libunwind: + + CMake is the only supported configuration system. + + Clang is the preferred compiler when building and using libunwind. + + * ``cd where you want to build llvm`` + * ``mkdir build`` + * ``cd build`` + * ``cmake -G -DLLVM_ENABLE_PROJECTS=libunwind [options] `` + + For more information about configuring libunwind see :ref:`CMake Options`. + + * ``make unwind`` --- will build libunwind. + * ``make check-unwind`` --- will run the test suite. + + Shared and static libraries for libunwind should now be present in llvm/build/lib. + +#. **Optional**: Install libunwind + + If your system already provides an unwinder, it is important to be careful + not to replace it. Remember Use the CMake option ``CMAKE_INSTALL_PREFIX`` to + select a safe place to install libunwind. + + * ``make install-unwind`` --- Will install the libraries and the headers + + +It is sometimes beneficial to build outside of the LLVM tree. An out-of-tree +build would look like this: + +.. code-block:: bash + + $ cd where-you-want-libunwind-to-live + $ # Check out llvm, and libunwind + $ ``svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm`` + $ ``svn co https://llvm.org/svn/llvm-project/libunwind/trunk libunwind`` + $ cd where-you-want-to-build + $ mkdir build && cd build + $ export CC=clang CXX=clang++ + $ cmake -DLLVM_PATH=path/to/llvm \ + path/to/libunwind + $ make + + +.. _CMake Options: + +CMake Options +============= + +Here are some of the CMake variables that are used often, along with a +brief explanation and LLVM-specific notes. For full documentation, check the +CMake docs or execute ``cmake --help-variable VARIABLE_NAME``. + +**CMAKE_BUILD_TYPE**:STRING + Sets the build type for ``make`` based generators. Possible values are + Release, Debug, RelWithDebInfo and MinSizeRel. On systems like Visual Studio + the user sets the build type with the IDE settings. + +**CMAKE_INSTALL_PREFIX**:PATH + Path where LLVM will be installed if "make install" is invoked or the + "INSTALL" target is built. + +**CMAKE_CXX_COMPILER**:STRING + The C++ compiler to use when building and testing libunwind. + + +.. _libunwind-specific options: + +libunwind specific options +-------------------------- + +.. option:: LIBUNWIND_BUILD_32_BITS:BOOL + + **Default**: Same as LLVM_BUILD_32_BITS + + Toggle whether libunwind should be built with -m32. + +.. option:: LIBUNWIND_ENABLE_ASSERTIONS:BOOL + + **Default**: ``ON`` + + Toggle assertions independent of the build mode. + +.. option:: LIBUNWIND_ENABLE_PEDANTIC:BOOL + + **Default**: ``ON`` + + Compile with -Wpedantic. + +.. option:: LIBUNWIND_ENABLE_WERROR:BOOL + + **Default**: ``ON`` + + Compile with -Werror + +.. option:: LIBUNWIND_ENABLE_SHARED:BOOL + + **Default**: ``ON`` + + Build libunwind as a shared library. + +.. option:: LIBUNWIND_ENABLE_STATIC:BOOL + + **Default**: ``ON`` + + Build libunwind as a static archive. + +.. option:: LIBUNWIND_ENABLE_CROSS_UNWINDING:BOOL + + **Default**: ``OFF`` + + Enable cross-platform unwinding support. + +.. option:: LIBUNWIND_ENABLE_ARM_WMMX:BOOL + + **Default**: ``OFF`` + + Enable unwinding support for ARM WMMX registers. + +.. option:: LIBUNWIND_ENABLE_THREADS:BOOL + + **Default**: ``ON`` + + Build libunwind with threading support. + +.. option:: LIBUNWIND_TARGET_TRIPLE:STRING + + Target triple for cross compiling + +.. option:: LIBUNWIND_GCC_TOOLCHAIN:PATH + + GCC toolchain for cross compiling + +.. option:: LIBUNWIND_SYSROOT + + Sysroot for cross compiling + +.. option:: LIBUNWIND_INSTALL_LIBRARY_DIR:PATH + + **Default**: ``lib${LIBUNWIND_LIBDIR_SUFFIX}`` + + Path where built libunwind libraries should be installed. If a relative path, + relative to ``CMAKE_INSTALL_PREFIX``. diff --git a/libunwind/docs/CMakeLists.txt b/libunwind/docs/CMakeLists.txt new file mode 100644 index 0000000000..79b87eb03b --- /dev/null +++ b/libunwind/docs/CMakeLists.txt @@ -0,0 +1,7 @@ +include(FindSphinx) +if (SPHINX_FOUND AND LLVM_ENABLE_SPHINX) + include(AddSphinxTarget) + if (${SPHINX_OUTPUT_HTML}) + add_sphinx_target(html libunwind) + endif() +endif() diff --git a/libunwind/docs/README.txt b/libunwind/docs/README.txt new file mode 100644 index 0000000000..968982fce5 --- /dev/null +++ b/libunwind/docs/README.txt @@ -0,0 +1,13 @@ +libunwind Documentation +==================== + +The libunwind documentation is written using the Sphinx documentation generator. It is +currently tested with Sphinx 1.1.3. + +To build the documents into html configure libunwind with the following cmake options: + + * -DLLVM_ENABLE_SPHINX=ON + * -DLIBUNWIND_INCLUDE_DOCS=ON + +After configuring libunwind with these options the make rule `docs-libunwind-html` +should be available. diff --git a/libunwind/docs/conf.py b/libunwind/docs/conf.py new file mode 100644 index 0000000000..bc91d90fe8 --- /dev/null +++ b/libunwind/docs/conf.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- +# +# libunwind documentation build configuration file. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +from datetime import date + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'libunwind' +copyright = u'2011-%d, LLVM Project' % date.today().year + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '14.0' +# The full version, including alpha/beta/rc tags. +release = '14.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'friendly' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libunwinddoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('contents', 'libunwind.tex', u'libunwind Documentation', + u'LLVM project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('contents', 'libunwind', u'libunwind Documentation', + [u'LLVM project'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('contents', 'libunwind', u'libunwind Documentation', + u'LLVM project', 'libunwind', 'LLVM Unwinder', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# FIXME: Define intersphinx configration. +intersphinx_mapping = {} + + +# -- Options for extensions ---------------------------------------------------- + +# Enable this if you want TODOs to show up in the generated documentation. +todo_include_todos = True diff --git a/libunwind/docs/index.rst b/libunwind/docs/index.rst new file mode 100644 index 0000000000..f7ff29d095 --- /dev/null +++ b/libunwind/docs/index.rst @@ -0,0 +1,104 @@ +.. _index: + +======================= +libunwind LLVM Unwinder +======================= + +Overview +======== + +libunwind is an implementation of the interface defined by the HP libunwind +project. It was contributed by Apple as a way to enable clang++ to port to +platforms that do not have a system unwinder. It is intended to be a small and +fast implementation of the ABI, leaving off some features of HP's libunwind +that never materialized (e.g. remote unwinding). + +The unwinder has two levels of API. The high level APIs are the `_Unwind_*` +functions which implement functionality required by `__cxa_*` exception +functions. The low level APIs are the `unw_*` functions which are an interface +defined by the old HP libunwind project. + +Getting Started with libunwind +------------------------------ + +.. toctree:: + :maxdepth: 2 + + BuildingLibunwind + +Current Status +-------------- + +libunwind is a production-quality unwinder, with platform support for DWARF +unwind info, SjLj, and ARM EHABI. + +The low level libunwind API was designed to work either in-process (aka local) +or to operate on another process (aka remote), but only the local path has been +implemented. Remote unwinding remains as future work. + +Platform and Compiler Support +----------------------------- + +libunwind is known to work on the following platforms: + +============ ======================== ============ ======================== +OS Arch Compilers Unwind Info +============ ======================== ============ ======================== +Any i386, x86_64, ARM Clang SjLj +Bare Metal ARM Clang, GCC EHABI +FreeBSD i386, x86_64, ARM64 Clang DWARF CFI +iOS ARM Clang SjLj +Linux ARM Clang, GCC EHABI +Linux i386, x86_64, ARM64 Clang, GCC DWARF CFI +macOS i386, x86_64 Clang, GCC DWARF CFI +NetBSD x86_64 Clang, GCC DWARF CFI +Windows i386, x86_64, ARM, ARM64 Clang DWARF CFI +============ ======================== ============ ======================== + +The following minimum compiler versions are strongly recommended. + +* Clang 3.5 and above +* GCC 4.7 and above. + +Anything older *may* work. + +Notes and Known Issues +---------------------- + +* TODO + + +Getting Involved +================ + +First please review our `Developer's Policy `__ +and `Getting started with LLVM `__. + +**Bug Reports** + +If you think you've found a bug in libunwind, please report it using +the `LLVM Bugzilla`_. If you're not sure, you +can post a message to the `cfe-dev mailing list`_ or on IRC. +Please include "libunwind" in your subject. + +**Patches** + +If you want to contribute a patch to libunwind, the best place for that is +`Phabricator `_. Please include [libunwind] in the subject and +add `cfe-commits` as a subscriber. Also make sure you are subscribed to the +`cfe-commits mailing list `_. + +**Discussion and Questions** + +Send discussions and questions to the +`cfe-dev mailing list `_. +Please include [libunwind] in the subject. + + +Quick Links +=========== +* `LLVM Homepage `_ +* `LLVM Bugzilla `_ +* `cfe-commits Mailing List`_ +* `cfe-dev Mailing List`_ +* `Browse libunwind Sources `_ diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h new file mode 100644 index 0000000000..a50ba05388 --- /dev/null +++ b/libunwind/include/__libunwind_config.h @@ -0,0 +1,176 @@ +//===------------------------- __libunwind_config.h -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef ____LIBUNWIND_CONFIG_H__ +#define ____LIBUNWIND_CONFIG_H__ + +#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ + !defined(__ARM_DWARF_EH__) +#define _LIBUNWIND_ARM_EHABI +#endif + +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64 +#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143 + +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__linux__) +# define _LIBUNWIND_TARGET_LINUX 1 +# endif +# if defined(__i386__) +# define _LIBUNWIND_TARGET_I386 +# define _LIBUNWIND_CONTEXT_SIZE 8 +# define _LIBUNWIND_CURSOR_SIZE 15 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 +# elif defined(__x86_64__) +# define _LIBUNWIND_TARGET_X86_64 1 +# if defined(_WIN64) +# define _LIBUNWIND_CONTEXT_SIZE 54 +# ifdef __SEH__ +# define _LIBUNWIND_CURSOR_SIZE 204 +# else +# define _LIBUNWIND_CURSOR_SIZE 66 +# endif +# else +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 +# elif defined(__powerpc64__) +# define _LIBUNWIND_TARGET_PPC64 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 +# elif defined(__ppc__) +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_CONTEXT_SIZE 117 +# define _LIBUNWIND_CURSOR_SIZE 124 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC +# elif defined(__aarch64__) +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_CONTEXT_SIZE 66 +# if defined(__SEH__) +# define _LIBUNWIND_CURSOR_SIZE 164 +# else +# define _LIBUNWIND_CURSOR_SIZE 78 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 +# elif defined(__arm__) +# define _LIBUNWIND_TARGET_ARM 1 +# if defined(__SEH__) +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 80 +# elif defined(__ARM_WMMX) +# define _LIBUNWIND_CONTEXT_SIZE 61 +# define _LIBUNWIND_CURSOR_SIZE 68 +# else +# define _LIBUNWIND_CONTEXT_SIZE 42 +# define _LIBUNWIND_CURSOR_SIZE 49 +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM +# elif defined(__or1k__) +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 16 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K +# elif defined(__hexagon__) +# define _LIBUNWIND_TARGET_HEXAGON 1 +// Values here change when : Registers.hpp - hexagon_thread_state_t change +# define _LIBUNWIND_CONTEXT_SIZE 18 +# define _LIBUNWIND_CURSOR_SIZE 24 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON +# elif defined(__mips__) +# if defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 50 +# define _LIBUNWIND_CURSOR_SIZE 57 +# else +# define _LIBUNWIND_CONTEXT_SIZE 18 +# define _LIBUNWIND_CURSOR_SIZE 24 +# endif +# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 74 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 42 +# endif +# elif defined(_ABI64) && _MIPS_SIM == _ABI64 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# if defined(__mips_hard_float) +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 79 +# else +# define _LIBUNWIND_CONTEXT_SIZE 35 +# define _LIBUNWIND_CURSOR_SIZE 47 +# endif +# else +# error "Unsupported MIPS ABI and/or environment" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS +# elif defined(__sparc__) + #define _LIBUNWIND_TARGET_SPARC 1 + #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC + #define _LIBUNWIND_CONTEXT_SIZE 16 + #define _LIBUNWIND_CURSOR_SIZE 23 +# elif defined(__riscv) +# define _LIBUNWIND_TARGET_RISCV 1 +# if defined(__riscv_flen) +# define RISCV_FLEN __riscv_flen +# else +# define RISCV_FLEN 0 +# endif +# define _LIBUNWIND_CONTEXT_SIZE (32 * (__riscv_xlen + RISCV_FLEN) / 64) +# if __riscv_xlen == 32 +# define _LIBUNWIND_CURSOR_SIZE (_LIBUNWIND_CONTEXT_SIZE + 7) +# elif __riscv_xlen == 64 +# define _LIBUNWIND_CURSOR_SIZE (_LIBUNWIND_CONTEXT_SIZE + 12) +# else +# error "Unsupported RISC-V ABI" +# endif +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV +# elif defined(__ve__) +# define _LIBUNWIND_TARGET_VE 1 +# define _LIBUNWIND_CONTEXT_SIZE 67 +# define _LIBUNWIND_CURSOR_SIZE 79 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE +# else +# error "Unsupported architecture." +# endif +#else // !_LIBUNWIND_IS_NATIVE_ONLY +# define _LIBUNWIND_TARGET_I386 +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_PPC64 1 +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_TARGET_MIPS_O32 1 +# define _LIBUNWIND_TARGET_MIPS_NEWABI 1 +# define _LIBUNWIND_TARGET_SPARC 1 +# define _LIBUNWIND_TARGET_HEXAGON 1 +# define _LIBUNWIND_TARGET_RISCV 1 +# define _LIBUNWIND_TARGET_VE 1 +# define _LIBUNWIND_CONTEXT_SIZE 167 +# define _LIBUNWIND_CURSOR_SIZE 179 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287 +#endif // _LIBUNWIND_IS_NATIVE_ONLY + +#endif // ____LIBUNWIND_CONFIG_H__ diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h new file mode 100644 index 0000000000..5ba63e5b7e --- /dev/null +++ b/libunwind/include/libunwind.h @@ -0,0 +1,1176 @@ +//===---------------------------- libunwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Compatible with libunwind API documented at: +// http://www.nongnu.org/libunwind/man/libunwind(3).html +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBUNWIND__ +#define __LIBUNWIND__ + +#include <__libunwind_config.h> + +#include +#include + +#ifdef __APPLE__ + #if __clang__ + #if __has_include() + #include + #endif + #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 + #include + #endif + + #ifdef __arm__ + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #elif defined(__OSX_AVAILABLE_STARTING) + #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #else + #include + #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #else + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #endif + #endif +#else + #define LIBUNWIND_AVAIL +#endif + +#if defined(_WIN32) && defined(__SEH__) + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16))) +#else + #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR +#endif + +/* error codes */ +enum { + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC = -6540, /* unspecified (general) error */ + UNW_ENOMEM = -6541, /* out of memory */ + UNW_EBADREG = -6542, /* bad register number */ + UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ + UNW_ESTOPUNWIND = -6544, /* stop unwinding */ + UNW_EINVALIDIP = -6545, /* invalid IP */ + UNW_EBADFRAME = -6546, /* bad frame */ + UNW_EINVAL = -6547, /* unsupported operation or bad value */ + UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ + UNW_ENOINFO = -6549 /* no unwind info found */ +#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY) + , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */ +#endif +}; + +struct unw_context_t { + uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; +}; +typedef struct unw_context_t unw_context_t; + +struct unw_cursor_t { + uint64_t data[_LIBUNWIND_CURSOR_SIZE]; +} LIBUNWIND_CURSOR_ALIGNMENT_ATTR; +typedef struct unw_cursor_t unw_cursor_t; + +typedef struct unw_addr_space *unw_addr_space_t; + +typedef int unw_regnum_t; +typedef uintptr_t unw_word_t; +#if defined(__arm__) && !defined(__ARM_DWARF_EH__) +typedef uint64_t unw_fpreg_t; +#else +typedef double unw_fpreg_t; +#endif + +struct unw_proc_info_t { + unw_word_t start_ip; /* start address of function */ + unw_word_t end_ip; /* address after end of function */ + unw_word_t lsda; /* address of language specific data area, */ + /* or zero if not used */ + unw_word_t handler; /* personality routine, or zero if not used */ + unw_word_t gp; /* not used */ + unw_word_t flags; /* not used */ + uint32_t format; /* compact unwind encoding, or zero if none */ + uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */ + unw_word_t unwind_info; /* address of DWARF unwind info, or zero */ + unw_word_t extra; /* mach_header of mach-o image containing func */ +}; +typedef struct unw_proc_info_t unw_proc_info_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; +extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; +extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; +extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; +extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; + +#ifdef __arm__ +/* Save VFP registers in FSTMX format (instead of FSTMD). */ +extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; +#endif + + +extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; +extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; +//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); + +extern unw_addr_space_t unw_local_addr_space; + +#ifdef __cplusplus +} +#endif + +// architecture independent register numbers +enum { + UNW_REG_IP = -1, // instruction pointer + UNW_REG_SP = -2, // stack pointer +}; + +// 32-bit x86 registers +enum { + UNW_X86_EAX = 0, + UNW_X86_ECX = 1, + UNW_X86_EDX = 2, + UNW_X86_EBX = 3, + UNW_X86_EBP = 4, + UNW_X86_ESP = 5, + UNW_X86_ESI = 6, + UNW_X86_EDI = 7 +}; + +// 64-bit x86_64 registers +enum { + UNW_X86_64_RAX = 0, + UNW_X86_64_RDX = 1, + UNW_X86_64_RCX = 2, + UNW_X86_64_RBX = 3, + UNW_X86_64_RSI = 4, + UNW_X86_64_RDI = 5, + UNW_X86_64_RBP = 6, + UNW_X86_64_RSP = 7, + UNW_X86_64_R8 = 8, + UNW_X86_64_R9 = 9, + UNW_X86_64_R10 = 10, + UNW_X86_64_R11 = 11, + UNW_X86_64_R12 = 12, + UNW_X86_64_R13 = 13, + UNW_X86_64_R14 = 14, + UNW_X86_64_R15 = 15, + UNW_X86_64_RIP = 16, + UNW_X86_64_XMM0 = 17, + UNW_X86_64_XMM1 = 18, + UNW_X86_64_XMM2 = 19, + UNW_X86_64_XMM3 = 20, + UNW_X86_64_XMM4 = 21, + UNW_X86_64_XMM5 = 22, + UNW_X86_64_XMM6 = 23, + UNW_X86_64_XMM7 = 24, + UNW_X86_64_XMM8 = 25, + UNW_X86_64_XMM9 = 26, + UNW_X86_64_XMM10 = 27, + UNW_X86_64_XMM11 = 28, + UNW_X86_64_XMM12 = 29, + UNW_X86_64_XMM13 = 30, + UNW_X86_64_XMM14 = 31, + UNW_X86_64_XMM15 = 32, +}; + + +// 32-bit ppc register numbers +enum { + UNW_PPC_R0 = 0, + UNW_PPC_R1 = 1, + UNW_PPC_R2 = 2, + UNW_PPC_R3 = 3, + UNW_PPC_R4 = 4, + UNW_PPC_R5 = 5, + UNW_PPC_R6 = 6, + UNW_PPC_R7 = 7, + UNW_PPC_R8 = 8, + UNW_PPC_R9 = 9, + UNW_PPC_R10 = 10, + UNW_PPC_R11 = 11, + UNW_PPC_R12 = 12, + UNW_PPC_R13 = 13, + UNW_PPC_R14 = 14, + UNW_PPC_R15 = 15, + UNW_PPC_R16 = 16, + UNW_PPC_R17 = 17, + UNW_PPC_R18 = 18, + UNW_PPC_R19 = 19, + UNW_PPC_R20 = 20, + UNW_PPC_R21 = 21, + UNW_PPC_R22 = 22, + UNW_PPC_R23 = 23, + UNW_PPC_R24 = 24, + UNW_PPC_R25 = 25, + UNW_PPC_R26 = 26, + UNW_PPC_R27 = 27, + UNW_PPC_R28 = 28, + UNW_PPC_R29 = 29, + UNW_PPC_R30 = 30, + UNW_PPC_R31 = 31, + UNW_PPC_F0 = 32, + UNW_PPC_F1 = 33, + UNW_PPC_F2 = 34, + UNW_PPC_F3 = 35, + UNW_PPC_F4 = 36, + UNW_PPC_F5 = 37, + UNW_PPC_F6 = 38, + UNW_PPC_F7 = 39, + UNW_PPC_F8 = 40, + UNW_PPC_F9 = 41, + UNW_PPC_F10 = 42, + UNW_PPC_F11 = 43, + UNW_PPC_F12 = 44, + UNW_PPC_F13 = 45, + UNW_PPC_F14 = 46, + UNW_PPC_F15 = 47, + UNW_PPC_F16 = 48, + UNW_PPC_F17 = 49, + UNW_PPC_F18 = 50, + UNW_PPC_F19 = 51, + UNW_PPC_F20 = 52, + UNW_PPC_F21 = 53, + UNW_PPC_F22 = 54, + UNW_PPC_F23 = 55, + UNW_PPC_F24 = 56, + UNW_PPC_F25 = 57, + UNW_PPC_F26 = 58, + UNW_PPC_F27 = 59, + UNW_PPC_F28 = 60, + UNW_PPC_F29 = 61, + UNW_PPC_F30 = 62, + UNW_PPC_F31 = 63, + UNW_PPC_MQ = 64, + UNW_PPC_LR = 65, + UNW_PPC_CTR = 66, + UNW_PPC_AP = 67, + UNW_PPC_CR0 = 68, + UNW_PPC_CR1 = 69, + UNW_PPC_CR2 = 70, + UNW_PPC_CR3 = 71, + UNW_PPC_CR4 = 72, + UNW_PPC_CR5 = 73, + UNW_PPC_CR6 = 74, + UNW_PPC_CR7 = 75, + UNW_PPC_XER = 76, + UNW_PPC_V0 = 77, + UNW_PPC_V1 = 78, + UNW_PPC_V2 = 79, + UNW_PPC_V3 = 80, + UNW_PPC_V4 = 81, + UNW_PPC_V5 = 82, + UNW_PPC_V6 = 83, + UNW_PPC_V7 = 84, + UNW_PPC_V8 = 85, + UNW_PPC_V9 = 86, + UNW_PPC_V10 = 87, + UNW_PPC_V11 = 88, + UNW_PPC_V12 = 89, + UNW_PPC_V13 = 90, + UNW_PPC_V14 = 91, + UNW_PPC_V15 = 92, + UNW_PPC_V16 = 93, + UNW_PPC_V17 = 94, + UNW_PPC_V18 = 95, + UNW_PPC_V19 = 96, + UNW_PPC_V20 = 97, + UNW_PPC_V21 = 98, + UNW_PPC_V22 = 99, + UNW_PPC_V23 = 100, + UNW_PPC_V24 = 101, + UNW_PPC_V25 = 102, + UNW_PPC_V26 = 103, + UNW_PPC_V27 = 104, + UNW_PPC_V28 = 105, + UNW_PPC_V29 = 106, + UNW_PPC_V30 = 107, + UNW_PPC_V31 = 108, + UNW_PPC_VRSAVE = 109, + UNW_PPC_VSCR = 110, + UNW_PPC_SPE_ACC = 111, + UNW_PPC_SPEFSCR = 112 +}; + +// 64-bit ppc register numbers +enum { + UNW_PPC64_R0 = 0, + UNW_PPC64_R1 = 1, + UNW_PPC64_R2 = 2, + UNW_PPC64_R3 = 3, + UNW_PPC64_R4 = 4, + UNW_PPC64_R5 = 5, + UNW_PPC64_R6 = 6, + UNW_PPC64_R7 = 7, + UNW_PPC64_R8 = 8, + UNW_PPC64_R9 = 9, + UNW_PPC64_R10 = 10, + UNW_PPC64_R11 = 11, + UNW_PPC64_R12 = 12, + UNW_PPC64_R13 = 13, + UNW_PPC64_R14 = 14, + UNW_PPC64_R15 = 15, + UNW_PPC64_R16 = 16, + UNW_PPC64_R17 = 17, + UNW_PPC64_R18 = 18, + UNW_PPC64_R19 = 19, + UNW_PPC64_R20 = 20, + UNW_PPC64_R21 = 21, + UNW_PPC64_R22 = 22, + UNW_PPC64_R23 = 23, + UNW_PPC64_R24 = 24, + UNW_PPC64_R25 = 25, + UNW_PPC64_R26 = 26, + UNW_PPC64_R27 = 27, + UNW_PPC64_R28 = 28, + UNW_PPC64_R29 = 29, + UNW_PPC64_R30 = 30, + UNW_PPC64_R31 = 31, + UNW_PPC64_F0 = 32, + UNW_PPC64_F1 = 33, + UNW_PPC64_F2 = 34, + UNW_PPC64_F3 = 35, + UNW_PPC64_F4 = 36, + UNW_PPC64_F5 = 37, + UNW_PPC64_F6 = 38, + UNW_PPC64_F7 = 39, + UNW_PPC64_F8 = 40, + UNW_PPC64_F9 = 41, + UNW_PPC64_F10 = 42, + UNW_PPC64_F11 = 43, + UNW_PPC64_F12 = 44, + UNW_PPC64_F13 = 45, + UNW_PPC64_F14 = 46, + UNW_PPC64_F15 = 47, + UNW_PPC64_F16 = 48, + UNW_PPC64_F17 = 49, + UNW_PPC64_F18 = 50, + UNW_PPC64_F19 = 51, + UNW_PPC64_F20 = 52, + UNW_PPC64_F21 = 53, + UNW_PPC64_F22 = 54, + UNW_PPC64_F23 = 55, + UNW_PPC64_F24 = 56, + UNW_PPC64_F25 = 57, + UNW_PPC64_F26 = 58, + UNW_PPC64_F27 = 59, + UNW_PPC64_F28 = 60, + UNW_PPC64_F29 = 61, + UNW_PPC64_F30 = 62, + UNW_PPC64_F31 = 63, + // 64: reserved + UNW_PPC64_LR = 65, + UNW_PPC64_CTR = 66, + // 67: reserved + UNW_PPC64_CR0 = 68, + UNW_PPC64_CR1 = 69, + UNW_PPC64_CR2 = 70, + UNW_PPC64_CR3 = 71, + UNW_PPC64_CR4 = 72, + UNW_PPC64_CR5 = 73, + UNW_PPC64_CR6 = 74, + UNW_PPC64_CR7 = 75, + UNW_PPC64_XER = 76, + UNW_PPC64_V0 = 77, + UNW_PPC64_V1 = 78, + UNW_PPC64_V2 = 79, + UNW_PPC64_V3 = 80, + UNW_PPC64_V4 = 81, + UNW_PPC64_V5 = 82, + UNW_PPC64_V6 = 83, + UNW_PPC64_V7 = 84, + UNW_PPC64_V8 = 85, + UNW_PPC64_V9 = 86, + UNW_PPC64_V10 = 87, + UNW_PPC64_V11 = 88, + UNW_PPC64_V12 = 89, + UNW_PPC64_V13 = 90, + UNW_PPC64_V14 = 91, + UNW_PPC64_V15 = 92, + UNW_PPC64_V16 = 93, + UNW_PPC64_V17 = 94, + UNW_PPC64_V18 = 95, + UNW_PPC64_V19 = 96, + UNW_PPC64_V20 = 97, + UNW_PPC64_V21 = 98, + UNW_PPC64_V22 = 99, + UNW_PPC64_V23 = 100, + UNW_PPC64_V24 = 101, + UNW_PPC64_V25 = 102, + UNW_PPC64_V26 = 103, + UNW_PPC64_V27 = 104, + UNW_PPC64_V28 = 105, + UNW_PPC64_V29 = 106, + UNW_PPC64_V30 = 107, + UNW_PPC64_V31 = 108, + // 109, 111-113: OpenPOWER ELF V2 ABI: reserved + // Borrowing VRSAVE number from PPC32. + UNW_PPC64_VRSAVE = 109, + UNW_PPC64_VSCR = 110, + UNW_PPC64_TFHAR = 114, + UNW_PPC64_TFIAR = 115, + UNW_PPC64_TEXASR = 116, + UNW_PPC64_VS0 = UNW_PPC64_F0, + UNW_PPC64_VS1 = UNW_PPC64_F1, + UNW_PPC64_VS2 = UNW_PPC64_F2, + UNW_PPC64_VS3 = UNW_PPC64_F3, + UNW_PPC64_VS4 = UNW_PPC64_F4, + UNW_PPC64_VS5 = UNW_PPC64_F5, + UNW_PPC64_VS6 = UNW_PPC64_F6, + UNW_PPC64_VS7 = UNW_PPC64_F7, + UNW_PPC64_VS8 = UNW_PPC64_F8, + UNW_PPC64_VS9 = UNW_PPC64_F9, + UNW_PPC64_VS10 = UNW_PPC64_F10, + UNW_PPC64_VS11 = UNW_PPC64_F11, + UNW_PPC64_VS12 = UNW_PPC64_F12, + UNW_PPC64_VS13 = UNW_PPC64_F13, + UNW_PPC64_VS14 = UNW_PPC64_F14, + UNW_PPC64_VS15 = UNW_PPC64_F15, + UNW_PPC64_VS16 = UNW_PPC64_F16, + UNW_PPC64_VS17 = UNW_PPC64_F17, + UNW_PPC64_VS18 = UNW_PPC64_F18, + UNW_PPC64_VS19 = UNW_PPC64_F19, + UNW_PPC64_VS20 = UNW_PPC64_F20, + UNW_PPC64_VS21 = UNW_PPC64_F21, + UNW_PPC64_VS22 = UNW_PPC64_F22, + UNW_PPC64_VS23 = UNW_PPC64_F23, + UNW_PPC64_VS24 = UNW_PPC64_F24, + UNW_PPC64_VS25 = UNW_PPC64_F25, + UNW_PPC64_VS26 = UNW_PPC64_F26, + UNW_PPC64_VS27 = UNW_PPC64_F27, + UNW_PPC64_VS28 = UNW_PPC64_F28, + UNW_PPC64_VS29 = UNW_PPC64_F29, + UNW_PPC64_VS30 = UNW_PPC64_F30, + UNW_PPC64_VS31 = UNW_PPC64_F31, + UNW_PPC64_VS32 = UNW_PPC64_V0, + UNW_PPC64_VS33 = UNW_PPC64_V1, + UNW_PPC64_VS34 = UNW_PPC64_V2, + UNW_PPC64_VS35 = UNW_PPC64_V3, + UNW_PPC64_VS36 = UNW_PPC64_V4, + UNW_PPC64_VS37 = UNW_PPC64_V5, + UNW_PPC64_VS38 = UNW_PPC64_V6, + UNW_PPC64_VS39 = UNW_PPC64_V7, + UNW_PPC64_VS40 = UNW_PPC64_V8, + UNW_PPC64_VS41 = UNW_PPC64_V9, + UNW_PPC64_VS42 = UNW_PPC64_V10, + UNW_PPC64_VS43 = UNW_PPC64_V11, + UNW_PPC64_VS44 = UNW_PPC64_V12, + UNW_PPC64_VS45 = UNW_PPC64_V13, + UNW_PPC64_VS46 = UNW_PPC64_V14, + UNW_PPC64_VS47 = UNW_PPC64_V15, + UNW_PPC64_VS48 = UNW_PPC64_V16, + UNW_PPC64_VS49 = UNW_PPC64_V17, + UNW_PPC64_VS50 = UNW_PPC64_V18, + UNW_PPC64_VS51 = UNW_PPC64_V19, + UNW_PPC64_VS52 = UNW_PPC64_V20, + UNW_PPC64_VS53 = UNW_PPC64_V21, + UNW_PPC64_VS54 = UNW_PPC64_V22, + UNW_PPC64_VS55 = UNW_PPC64_V23, + UNW_PPC64_VS56 = UNW_PPC64_V24, + UNW_PPC64_VS57 = UNW_PPC64_V25, + UNW_PPC64_VS58 = UNW_PPC64_V26, + UNW_PPC64_VS59 = UNW_PPC64_V27, + UNW_PPC64_VS60 = UNW_PPC64_V28, + UNW_PPC64_VS61 = UNW_PPC64_V29, + UNW_PPC64_VS62 = UNW_PPC64_V30, + UNW_PPC64_VS63 = UNW_PPC64_V31 +}; + +// 64-bit ARM64 registers +enum { + UNW_AARCH64_X0 = 0, + UNW_AARCH64_X1 = 1, + UNW_AARCH64_X2 = 2, + UNW_AARCH64_X3 = 3, + UNW_AARCH64_X4 = 4, + UNW_AARCH64_X5 = 5, + UNW_AARCH64_X6 = 6, + UNW_AARCH64_X7 = 7, + UNW_AARCH64_X8 = 8, + UNW_AARCH64_X9 = 9, + UNW_AARCH64_X10 = 10, + UNW_AARCH64_X11 = 11, + UNW_AARCH64_X12 = 12, + UNW_AARCH64_X13 = 13, + UNW_AARCH64_X14 = 14, + UNW_AARCH64_X15 = 15, + UNW_AARCH64_X16 = 16, + UNW_AARCH64_X17 = 17, + UNW_AARCH64_X18 = 18, + UNW_AARCH64_X19 = 19, + UNW_AARCH64_X20 = 20, + UNW_AARCH64_X21 = 21, + UNW_AARCH64_X22 = 22, + UNW_AARCH64_X23 = 23, + UNW_AARCH64_X24 = 24, + UNW_AARCH64_X25 = 25, + UNW_AARCH64_X26 = 26, + UNW_AARCH64_X27 = 27, + UNW_AARCH64_X28 = 28, + UNW_AARCH64_X29 = 29, + UNW_AARCH64_FP = 29, + UNW_AARCH64_X30 = 30, + UNW_AARCH64_LR = 30, + UNW_AARCH64_X31 = 31, + UNW_AARCH64_SP = 31, + UNW_AARCH64_PC = 32, + + // reserved block + UNW_AARCH64_RA_SIGN_STATE = 34, + + // FP/vector registers + UNW_AARCH64_V0 = 64, + UNW_AARCH64_V1 = 65, + UNW_AARCH64_V2 = 66, + UNW_AARCH64_V3 = 67, + UNW_AARCH64_V4 = 68, + UNW_AARCH64_V5 = 69, + UNW_AARCH64_V6 = 70, + UNW_AARCH64_V7 = 71, + UNW_AARCH64_V8 = 72, + UNW_AARCH64_V9 = 73, + UNW_AARCH64_V10 = 74, + UNW_AARCH64_V11 = 75, + UNW_AARCH64_V12 = 76, + UNW_AARCH64_V13 = 77, + UNW_AARCH64_V14 = 78, + UNW_AARCH64_V15 = 79, + UNW_AARCH64_V16 = 80, + UNW_AARCH64_V17 = 81, + UNW_AARCH64_V18 = 82, + UNW_AARCH64_V19 = 83, + UNW_AARCH64_V20 = 84, + UNW_AARCH64_V21 = 85, + UNW_AARCH64_V22 = 86, + UNW_AARCH64_V23 = 87, + UNW_AARCH64_V24 = 88, + UNW_AARCH64_V25 = 89, + UNW_AARCH64_V26 = 90, + UNW_AARCH64_V27 = 91, + UNW_AARCH64_V28 = 92, + UNW_AARCH64_V29 = 93, + UNW_AARCH64_V30 = 94, + UNW_AARCH64_V31 = 95, + + // Compatibility aliases + UNW_ARM64_X0 = UNW_AARCH64_X0, + UNW_ARM64_X1 = UNW_AARCH64_X1, + UNW_ARM64_X2 = UNW_AARCH64_X2, + UNW_ARM64_X3 = UNW_AARCH64_X3, + UNW_ARM64_X4 = UNW_AARCH64_X4, + UNW_ARM64_X5 = UNW_AARCH64_X5, + UNW_ARM64_X6 = UNW_AARCH64_X6, + UNW_ARM64_X7 = UNW_AARCH64_X7, + UNW_ARM64_X8 = UNW_AARCH64_X8, + UNW_ARM64_X9 = UNW_AARCH64_X9, + UNW_ARM64_X10 = UNW_AARCH64_X10, + UNW_ARM64_X11 = UNW_AARCH64_X11, + UNW_ARM64_X12 = UNW_AARCH64_X12, + UNW_ARM64_X13 = UNW_AARCH64_X13, + UNW_ARM64_X14 = UNW_AARCH64_X14, + UNW_ARM64_X15 = UNW_AARCH64_X15, + UNW_ARM64_X16 = UNW_AARCH64_X16, + UNW_ARM64_X17 = UNW_AARCH64_X17, + UNW_ARM64_X18 = UNW_AARCH64_X18, + UNW_ARM64_X19 = UNW_AARCH64_X19, + UNW_ARM64_X20 = UNW_AARCH64_X20, + UNW_ARM64_X21 = UNW_AARCH64_X21, + UNW_ARM64_X22 = UNW_AARCH64_X22, + UNW_ARM64_X23 = UNW_AARCH64_X23, + UNW_ARM64_X24 = UNW_AARCH64_X24, + UNW_ARM64_X25 = UNW_AARCH64_X25, + UNW_ARM64_X26 = UNW_AARCH64_X26, + UNW_ARM64_X27 = UNW_AARCH64_X27, + UNW_ARM64_X28 = UNW_AARCH64_X28, + UNW_ARM64_X29 = UNW_AARCH64_X29, + UNW_ARM64_FP = UNW_AARCH64_FP, + UNW_ARM64_X30 = UNW_AARCH64_X30, + UNW_ARM64_LR = UNW_AARCH64_LR, + UNW_ARM64_X31 = UNW_AARCH64_X31, + UNW_ARM64_SP = UNW_AARCH64_SP, + UNW_ARM64_PC = UNW_AARCH64_PC, + UNW_ARM64_RA_SIGN_STATE = UNW_AARCH64_RA_SIGN_STATE, + UNW_ARM64_D0 = UNW_AARCH64_V0, + UNW_ARM64_D1 = UNW_AARCH64_V1, + UNW_ARM64_D2 = UNW_AARCH64_V2, + UNW_ARM64_D3 = UNW_AARCH64_V3, + UNW_ARM64_D4 = UNW_AARCH64_V4, + UNW_ARM64_D5 = UNW_AARCH64_V5, + UNW_ARM64_D6 = UNW_AARCH64_V6, + UNW_ARM64_D7 = UNW_AARCH64_V7, + UNW_ARM64_D8 = UNW_AARCH64_V8, + UNW_ARM64_D9 = UNW_AARCH64_V9, + UNW_ARM64_D10 = UNW_AARCH64_V10, + UNW_ARM64_D11 = UNW_AARCH64_V11, + UNW_ARM64_D12 = UNW_AARCH64_V12, + UNW_ARM64_D13 = UNW_AARCH64_V13, + UNW_ARM64_D14 = UNW_AARCH64_V14, + UNW_ARM64_D15 = UNW_AARCH64_V15, + UNW_ARM64_D16 = UNW_AARCH64_V16, + UNW_ARM64_D17 = UNW_AARCH64_V17, + UNW_ARM64_D18 = UNW_AARCH64_V18, + UNW_ARM64_D19 = UNW_AARCH64_V19, + UNW_ARM64_D20 = UNW_AARCH64_V20, + UNW_ARM64_D21 = UNW_AARCH64_V21, + UNW_ARM64_D22 = UNW_AARCH64_V22, + UNW_ARM64_D23 = UNW_AARCH64_V23, + UNW_ARM64_D24 = UNW_AARCH64_V24, + UNW_ARM64_D25 = UNW_AARCH64_V25, + UNW_ARM64_D26 = UNW_AARCH64_V26, + UNW_ARM64_D27 = UNW_AARCH64_V27, + UNW_ARM64_D28 = UNW_AARCH64_V28, + UNW_ARM64_D29 = UNW_AARCH64_V29, + UNW_ARM64_D30 = UNW_AARCH64_V30, + UNW_ARM64_D31 = UNW_AARCH64_V31, +}; + +// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. +// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. +// In this scheme, even though the 64-bit floating point registers D0-D31 +// overlap physically with the 32-bit floating pointer registers S0-S31, +// they are given a non-overlapping range of register numbers. +// +// Commented out ranges are not preserved during unwinding. +enum { + UNW_ARM_R0 = 0, + UNW_ARM_R1 = 1, + UNW_ARM_R2 = 2, + UNW_ARM_R3 = 3, + UNW_ARM_R4 = 4, + UNW_ARM_R5 = 5, + UNW_ARM_R6 = 6, + UNW_ARM_R7 = 7, + UNW_ARM_R8 = 8, + UNW_ARM_R9 = 9, + UNW_ARM_R10 = 10, + UNW_ARM_R11 = 11, + UNW_ARM_R12 = 12, + UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP + UNW_ARM_R13 = 13, + UNW_ARM_LR = 14, + UNW_ARM_R14 = 14, + UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP + UNW_ARM_R15 = 15, + // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. + UNW_ARM_S0 = 64, + UNW_ARM_S1 = 65, + UNW_ARM_S2 = 66, + UNW_ARM_S3 = 67, + UNW_ARM_S4 = 68, + UNW_ARM_S5 = 69, + UNW_ARM_S6 = 70, + UNW_ARM_S7 = 71, + UNW_ARM_S8 = 72, + UNW_ARM_S9 = 73, + UNW_ARM_S10 = 74, + UNW_ARM_S11 = 75, + UNW_ARM_S12 = 76, + UNW_ARM_S13 = 77, + UNW_ARM_S14 = 78, + UNW_ARM_S15 = 79, + UNW_ARM_S16 = 80, + UNW_ARM_S17 = 81, + UNW_ARM_S18 = 82, + UNW_ARM_S19 = 83, + UNW_ARM_S20 = 84, + UNW_ARM_S21 = 85, + UNW_ARM_S22 = 86, + UNW_ARM_S23 = 87, + UNW_ARM_S24 = 88, + UNW_ARM_S25 = 89, + UNW_ARM_S26 = 90, + UNW_ARM_S27 = 91, + UNW_ARM_S28 = 92, + UNW_ARM_S29 = 93, + UNW_ARM_S30 = 94, + UNW_ARM_S31 = 95, + // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. + // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) + UNW_ARM_WR0 = 112, + UNW_ARM_WR1 = 113, + UNW_ARM_WR2 = 114, + UNW_ARM_WR3 = 115, + UNW_ARM_WR4 = 116, + UNW_ARM_WR5 = 117, + UNW_ARM_WR6 = 118, + UNW_ARM_WR7 = 119, + UNW_ARM_WR8 = 120, + UNW_ARM_WR9 = 121, + UNW_ARM_WR10 = 122, + UNW_ARM_WR11 = 123, + UNW_ARM_WR12 = 124, + UNW_ARM_WR13 = 125, + UNW_ARM_WR14 = 126, + UNW_ARM_WR15 = 127, + // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} + // 134-143 -- Reserved + // 144-150 -- R8_USR-R14_USR + // 151-157 -- R8_FIQ-R14_FIQ + // 158-159 -- R13_IRQ-R14_IRQ + // 160-161 -- R13_ABT-R14_ABT + // 162-163 -- R13_UND-R14_UND + // 164-165 -- R13_SVC-R14_SVC + // 166-191 -- Reserved + UNW_ARM_WC0 = 192, + UNW_ARM_WC1 = 193, + UNW_ARM_WC2 = 194, + UNW_ARM_WC3 = 195, + // 196-199 -- wC4-wC7 (Intel wireless MMX control) + // 200-255 -- Reserved + UNW_ARM_D0 = 256, + UNW_ARM_D1 = 257, + UNW_ARM_D2 = 258, + UNW_ARM_D3 = 259, + UNW_ARM_D4 = 260, + UNW_ARM_D5 = 261, + UNW_ARM_D6 = 262, + UNW_ARM_D7 = 263, + UNW_ARM_D8 = 264, + UNW_ARM_D9 = 265, + UNW_ARM_D10 = 266, + UNW_ARM_D11 = 267, + UNW_ARM_D12 = 268, + UNW_ARM_D13 = 269, + UNW_ARM_D14 = 270, + UNW_ARM_D15 = 271, + UNW_ARM_D16 = 272, + UNW_ARM_D17 = 273, + UNW_ARM_D18 = 274, + UNW_ARM_D19 = 275, + UNW_ARM_D20 = 276, + UNW_ARM_D21 = 277, + UNW_ARM_D22 = 278, + UNW_ARM_D23 = 279, + UNW_ARM_D24 = 280, + UNW_ARM_D25 = 281, + UNW_ARM_D26 = 282, + UNW_ARM_D27 = 283, + UNW_ARM_D28 = 284, + UNW_ARM_D29 = 285, + UNW_ARM_D30 = 286, + UNW_ARM_D31 = 287, + // 288-319 -- Reserved for VFP/Neon + // 320-8191 -- Reserved + // 8192-16383 -- Unspecified vendor co-processor register. +}; + +// OpenRISC1000 register numbers +enum { + UNW_OR1K_R0 = 0, + UNW_OR1K_R1 = 1, + UNW_OR1K_R2 = 2, + UNW_OR1K_R3 = 3, + UNW_OR1K_R4 = 4, + UNW_OR1K_R5 = 5, + UNW_OR1K_R6 = 6, + UNW_OR1K_R7 = 7, + UNW_OR1K_R8 = 8, + UNW_OR1K_R9 = 9, + UNW_OR1K_R10 = 10, + UNW_OR1K_R11 = 11, + UNW_OR1K_R12 = 12, + UNW_OR1K_R13 = 13, + UNW_OR1K_R14 = 14, + UNW_OR1K_R15 = 15, + UNW_OR1K_R16 = 16, + UNW_OR1K_R17 = 17, + UNW_OR1K_R18 = 18, + UNW_OR1K_R19 = 19, + UNW_OR1K_R20 = 20, + UNW_OR1K_R21 = 21, + UNW_OR1K_R22 = 22, + UNW_OR1K_R23 = 23, + UNW_OR1K_R24 = 24, + UNW_OR1K_R25 = 25, + UNW_OR1K_R26 = 26, + UNW_OR1K_R27 = 27, + UNW_OR1K_R28 = 28, + UNW_OR1K_R29 = 29, + UNW_OR1K_R30 = 30, + UNW_OR1K_R31 = 31, + UNW_OR1K_EPCR = 32, +}; + +// MIPS registers +enum { + UNW_MIPS_R0 = 0, + UNW_MIPS_R1 = 1, + UNW_MIPS_R2 = 2, + UNW_MIPS_R3 = 3, + UNW_MIPS_R4 = 4, + UNW_MIPS_R5 = 5, + UNW_MIPS_R6 = 6, + UNW_MIPS_R7 = 7, + UNW_MIPS_R8 = 8, + UNW_MIPS_R9 = 9, + UNW_MIPS_R10 = 10, + UNW_MIPS_R11 = 11, + UNW_MIPS_R12 = 12, + UNW_MIPS_R13 = 13, + UNW_MIPS_R14 = 14, + UNW_MIPS_R15 = 15, + UNW_MIPS_R16 = 16, + UNW_MIPS_R17 = 17, + UNW_MIPS_R18 = 18, + UNW_MIPS_R19 = 19, + UNW_MIPS_R20 = 20, + UNW_MIPS_R21 = 21, + UNW_MIPS_R22 = 22, + UNW_MIPS_R23 = 23, + UNW_MIPS_R24 = 24, + UNW_MIPS_R25 = 25, + UNW_MIPS_R26 = 26, + UNW_MIPS_R27 = 27, + UNW_MIPS_R28 = 28, + UNW_MIPS_R29 = 29, + UNW_MIPS_R30 = 30, + UNW_MIPS_R31 = 31, + UNW_MIPS_F0 = 32, + UNW_MIPS_F1 = 33, + UNW_MIPS_F2 = 34, + UNW_MIPS_F3 = 35, + UNW_MIPS_F4 = 36, + UNW_MIPS_F5 = 37, + UNW_MIPS_F6 = 38, + UNW_MIPS_F7 = 39, + UNW_MIPS_F8 = 40, + UNW_MIPS_F9 = 41, + UNW_MIPS_F10 = 42, + UNW_MIPS_F11 = 43, + UNW_MIPS_F12 = 44, + UNW_MIPS_F13 = 45, + UNW_MIPS_F14 = 46, + UNW_MIPS_F15 = 47, + UNW_MIPS_F16 = 48, + UNW_MIPS_F17 = 49, + UNW_MIPS_F18 = 50, + UNW_MIPS_F19 = 51, + UNW_MIPS_F20 = 52, + UNW_MIPS_F21 = 53, + UNW_MIPS_F22 = 54, + UNW_MIPS_F23 = 55, + UNW_MIPS_F24 = 56, + UNW_MIPS_F25 = 57, + UNW_MIPS_F26 = 58, + UNW_MIPS_F27 = 59, + UNW_MIPS_F28 = 60, + UNW_MIPS_F29 = 61, + UNW_MIPS_F30 = 62, + UNW_MIPS_F31 = 63, + UNW_MIPS_HI = 64, + UNW_MIPS_LO = 65, +}; + +// SPARC registers +enum { + UNW_SPARC_G0 = 0, + UNW_SPARC_G1 = 1, + UNW_SPARC_G2 = 2, + UNW_SPARC_G3 = 3, + UNW_SPARC_G4 = 4, + UNW_SPARC_G5 = 5, + UNW_SPARC_G6 = 6, + UNW_SPARC_G7 = 7, + UNW_SPARC_O0 = 8, + UNW_SPARC_O1 = 9, + UNW_SPARC_O2 = 10, + UNW_SPARC_O3 = 11, + UNW_SPARC_O4 = 12, + UNW_SPARC_O5 = 13, + UNW_SPARC_O6 = 14, + UNW_SPARC_O7 = 15, + UNW_SPARC_L0 = 16, + UNW_SPARC_L1 = 17, + UNW_SPARC_L2 = 18, + UNW_SPARC_L3 = 19, + UNW_SPARC_L4 = 20, + UNW_SPARC_L5 = 21, + UNW_SPARC_L6 = 22, + UNW_SPARC_L7 = 23, + UNW_SPARC_I0 = 24, + UNW_SPARC_I1 = 25, + UNW_SPARC_I2 = 26, + UNW_SPARC_I3 = 27, + UNW_SPARC_I4 = 28, + UNW_SPARC_I5 = 29, + UNW_SPARC_I6 = 30, + UNW_SPARC_I7 = 31, +}; + +// Hexagon register numbers +enum { + UNW_HEXAGON_R0, + UNW_HEXAGON_R1, + UNW_HEXAGON_R2, + UNW_HEXAGON_R3, + UNW_HEXAGON_R4, + UNW_HEXAGON_R5, + UNW_HEXAGON_R6, + UNW_HEXAGON_R7, + UNW_HEXAGON_R8, + UNW_HEXAGON_R9, + UNW_HEXAGON_R10, + UNW_HEXAGON_R11, + UNW_HEXAGON_R12, + UNW_HEXAGON_R13, + UNW_HEXAGON_R14, + UNW_HEXAGON_R15, + UNW_HEXAGON_R16, + UNW_HEXAGON_R17, + UNW_HEXAGON_R18, + UNW_HEXAGON_R19, + UNW_HEXAGON_R20, + UNW_HEXAGON_R21, + UNW_HEXAGON_R22, + UNW_HEXAGON_R23, + UNW_HEXAGON_R24, + UNW_HEXAGON_R25, + UNW_HEXAGON_R26, + UNW_HEXAGON_R27, + UNW_HEXAGON_R28, + UNW_HEXAGON_R29, + UNW_HEXAGON_R30, + UNW_HEXAGON_R31, + UNW_HEXAGON_P3_0, + UNW_HEXAGON_PC, +}; + +// RISC-V registers. These match the DWARF register numbers defined by section +// 4 of the RISC-V ELF psABI specification, which can be found at: +// +// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md +enum { + UNW_RISCV_X0 = 0, + UNW_RISCV_X1 = 1, + UNW_RISCV_X2 = 2, + UNW_RISCV_X3 = 3, + UNW_RISCV_X4 = 4, + UNW_RISCV_X5 = 5, + UNW_RISCV_X6 = 6, + UNW_RISCV_X7 = 7, + UNW_RISCV_X8 = 8, + UNW_RISCV_X9 = 9, + UNW_RISCV_X10 = 10, + UNW_RISCV_X11 = 11, + UNW_RISCV_X12 = 12, + UNW_RISCV_X13 = 13, + UNW_RISCV_X14 = 14, + UNW_RISCV_X15 = 15, + UNW_RISCV_X16 = 16, + UNW_RISCV_X17 = 17, + UNW_RISCV_X18 = 18, + UNW_RISCV_X19 = 19, + UNW_RISCV_X20 = 20, + UNW_RISCV_X21 = 21, + UNW_RISCV_X22 = 22, + UNW_RISCV_X23 = 23, + UNW_RISCV_X24 = 24, + UNW_RISCV_X25 = 25, + UNW_RISCV_X26 = 26, + UNW_RISCV_X27 = 27, + UNW_RISCV_X28 = 28, + UNW_RISCV_X29 = 29, + UNW_RISCV_X30 = 30, + UNW_RISCV_X31 = 31, + UNW_RISCV_F0 = 32, + UNW_RISCV_F1 = 33, + UNW_RISCV_F2 = 34, + UNW_RISCV_F3 = 35, + UNW_RISCV_F4 = 36, + UNW_RISCV_F5 = 37, + UNW_RISCV_F6 = 38, + UNW_RISCV_F7 = 39, + UNW_RISCV_F8 = 40, + UNW_RISCV_F9 = 41, + UNW_RISCV_F10 = 42, + UNW_RISCV_F11 = 43, + UNW_RISCV_F12 = 44, + UNW_RISCV_F13 = 45, + UNW_RISCV_F14 = 46, + UNW_RISCV_F15 = 47, + UNW_RISCV_F16 = 48, + UNW_RISCV_F17 = 49, + UNW_RISCV_F18 = 50, + UNW_RISCV_F19 = 51, + UNW_RISCV_F20 = 52, + UNW_RISCV_F21 = 53, + UNW_RISCV_F22 = 54, + UNW_RISCV_F23 = 55, + UNW_RISCV_F24 = 56, + UNW_RISCV_F25 = 57, + UNW_RISCV_F26 = 58, + UNW_RISCV_F27 = 59, + UNW_RISCV_F28 = 60, + UNW_RISCV_F29 = 61, + UNW_RISCV_F30 = 62, + UNW_RISCV_F31 = 63, +}; + +// VE register numbers +enum { + UNW_VE_S0 = 0, + UNW_VE_S1 = 1, + UNW_VE_S2 = 2, + UNW_VE_S3 = 3, + UNW_VE_S4 = 4, + UNW_VE_S5 = 5, + UNW_VE_S6 = 6, + UNW_VE_S7 = 7, + UNW_VE_S8 = 8, + UNW_VE_S9 = 9, + UNW_VE_S10 = 10, + UNW_VE_S11 = 11, + UNW_VE_S12 = 12, + UNW_VE_S13 = 13, + UNW_VE_S14 = 14, + UNW_VE_S15 = 15, + UNW_VE_S16 = 16, + UNW_VE_S17 = 17, + UNW_VE_S18 = 18, + UNW_VE_S19 = 19, + UNW_VE_S20 = 20, + UNW_VE_S21 = 21, + UNW_VE_S22 = 22, + UNW_VE_S23 = 23, + UNW_VE_S24 = 24, + UNW_VE_S25 = 25, + UNW_VE_S26 = 26, + UNW_VE_S27 = 27, + UNW_VE_S28 = 28, + UNW_VE_S29 = 29, + UNW_VE_S30 = 30, + UNW_VE_S31 = 31, + UNW_VE_S32 = 32, + UNW_VE_S33 = 33, + UNW_VE_S34 = 34, + UNW_VE_S35 = 35, + UNW_VE_S36 = 36, + UNW_VE_S37 = 37, + UNW_VE_S38 = 38, + UNW_VE_S39 = 39, + UNW_VE_S40 = 40, + UNW_VE_S41 = 41, + UNW_VE_S42 = 42, + UNW_VE_S43 = 43, + UNW_VE_S44 = 44, + UNW_VE_S45 = 45, + UNW_VE_S46 = 46, + UNW_VE_S47 = 47, + UNW_VE_S48 = 48, + UNW_VE_S49 = 49, + UNW_VE_S50 = 50, + UNW_VE_S51 = 51, + UNW_VE_S52 = 52, + UNW_VE_S53 = 53, + UNW_VE_S54 = 54, + UNW_VE_S55 = 55, + UNW_VE_S56 = 56, + UNW_VE_S57 = 57, + UNW_VE_S58 = 58, + UNW_VE_S59 = 59, + UNW_VE_S60 = 60, + UNW_VE_S61 = 61, + UNW_VE_S62 = 62, + UNW_VE_S63 = 63, + UNW_VE_V0 = 64 + 0, + UNW_VE_V1 = 64 + 1, + UNW_VE_V2 = 64 + 2, + UNW_VE_V3 = 64 + 3, + UNW_VE_V4 = 64 + 4, + UNW_VE_V5 = 64 + 5, + UNW_VE_V6 = 64 + 6, + UNW_VE_V7 = 64 + 7, + UNW_VE_V8 = 64 + 8, + UNW_VE_V9 = 64 + 9, + UNW_VE_V10 = 64 + 10, + UNW_VE_V11 = 64 + 11, + UNW_VE_V12 = 64 + 12, + UNW_VE_V13 = 64 + 13, + UNW_VE_V14 = 64 + 14, + UNW_VE_V15 = 64 + 15, + UNW_VE_V16 = 64 + 16, + UNW_VE_V17 = 64 + 17, + UNW_VE_V18 = 64 + 18, + UNW_VE_V19 = 64 + 19, + UNW_VE_V20 = 64 + 20, + UNW_VE_V21 = 64 + 21, + UNW_VE_V22 = 64 + 22, + UNW_VE_V23 = 64 + 23, + UNW_VE_V24 = 64 + 24, + UNW_VE_V25 = 64 + 25, + UNW_VE_V26 = 64 + 26, + UNW_VE_V27 = 64 + 27, + UNW_VE_V28 = 64 + 28, + UNW_VE_V29 = 64 + 29, + UNW_VE_V30 = 64 + 30, + UNW_VE_V31 = 64 + 31, + UNW_VE_V32 = 64 + 32, + UNW_VE_V33 = 64 + 33, + UNW_VE_V34 = 64 + 34, + UNW_VE_V35 = 64 + 35, + UNW_VE_V36 = 64 + 36, + UNW_VE_V37 = 64 + 37, + UNW_VE_V38 = 64 + 38, + UNW_VE_V39 = 64 + 39, + UNW_VE_V40 = 64 + 40, + UNW_VE_V41 = 64 + 41, + UNW_VE_V42 = 64 + 42, + UNW_VE_V43 = 64 + 43, + UNW_VE_V44 = 64 + 44, + UNW_VE_V45 = 64 + 45, + UNW_VE_V46 = 64 + 46, + UNW_VE_V47 = 64 + 47, + UNW_VE_V48 = 64 + 48, + UNW_VE_V49 = 64 + 49, + UNW_VE_V50 = 64 + 50, + UNW_VE_V51 = 64 + 51, + UNW_VE_V52 = 64 + 52, + UNW_VE_V53 = 64 + 53, + UNW_VE_V54 = 64 + 54, + UNW_VE_V55 = 64 + 55, + UNW_VE_V56 = 64 + 56, + UNW_VE_V57 = 64 + 57, + UNW_VE_V58 = 64 + 58, + UNW_VE_V59 = 64 + 59, + UNW_VE_V60 = 64 + 60, + UNW_VE_V61 = 64 + 61, + UNW_VE_V62 = 64 + 62, + UNW_VE_V63 = 64 + 63, + UNW_VE_VM0 = 128 + 0, + UNW_VE_VM1 = 128 + 1, + UNW_VE_VM2 = 128 + 2, + UNW_VE_VM3 = 128 + 3, + UNW_VE_VM4 = 128 + 4, + UNW_VE_VM5 = 128 + 5, + UNW_VE_VM6 = 128 + 6, + UNW_VE_VM7 = 128 + 7, + UNW_VE_VM8 = 128 + 8, + UNW_VE_VM9 = 128 + 9, + UNW_VE_VM10 = 128 + 10, + UNW_VE_VM11 = 128 + 11, + UNW_VE_VM12 = 128 + 12, + UNW_VE_VM13 = 128 + 13, + UNW_VE_VM14 = 128 + 14, + UNW_VE_VM15 = 128 + 15, // = 143 + + // Following registers don't have DWARF register numbers. + UNW_VE_VIXR = 144, + UNW_VE_VL = 145, +}; + +#endif diff --git a/libunwind/include/mach-o/compact_unwind_encoding.h b/libunwind/include/mach-o/compact_unwind_encoding.h new file mode 100644 index 0000000000..5301b1055e --- /dev/null +++ b/libunwind/include/mach-o/compact_unwind_encoding.h @@ -0,0 +1,477 @@ +//===------------------ mach-o/compact_unwind_encoding.h ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Darwin's alternative to DWARF based unwind encodings. +// +//===----------------------------------------------------------------------===// + + +#ifndef __COMPACT_UNWIND_ENCODING__ +#define __COMPACT_UNWIND_ENCODING__ + +#include + +// +// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section +// of object files. Or compilers can emit compact unwind information in +// the __LD,__compact_unwind section. +// +// When the linker creates a final linked image, it will create a +// __TEXT,__unwind_info section. This section is a small and fast way for the +// runtime to access unwind info for any given function. If the compiler +// emitted compact unwind info for the function, that compact unwind info will +// be encoded in the __TEXT,__unwind_info section. If the compiler emitted +// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset +// of the FDE in the __TEXT,__eh_frame section in the final linked image. +// +// Note: Previously, the linker would transform some DWARF unwind infos into +// compact unwind info. But that is fragile and no longer done. + + +// +// The compact unwind endoding is a 32-bit value which encoded in an +// architecture specific way, which registers to restore from where, and how +// to unwind out of the function. +// +typedef uint32_t compact_unwind_encoding_t; + + +// architecture independent bits +enum { + UNWIND_IS_NOT_FUNCTION_START = 0x80000000, + UNWIND_HAS_LSDA = 0x40000000, + UNWIND_PERSONALITY_MASK = 0x30000000, +}; + + + + +// +// x86 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF +// ebp based: +// 15-bits (5*3-bits per reg) register permutation +// 8-bits for stack offset +// frameless: +// 8-bits stack size +// 3-bits stack adjust +// 3-bits register count +// 10-bits register permutation +// +enum { + UNWIND_X86_MODE_MASK = 0x0F000000, + UNWIND_X86_MODE_EBP_FRAME = 0x01000000, + UNWIND_X86_MODE_STACK_IMMD = 0x02000000, + UNWIND_X86_MODE_STACK_IND = 0x03000000, + UNWIND_X86_MODE_DWARF = 0x04000000, + + UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, + UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, + + UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, + UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, + UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, + UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, + + UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; + +enum { + UNWIND_X86_REG_NONE = 0, + UNWIND_X86_REG_EBX = 1, + UNWIND_X86_REG_ECX = 2, + UNWIND_X86_REG_EDX = 3, + UNWIND_X86_REG_EDI = 4, + UNWIND_X86_REG_ESI = 5, + UNWIND_X86_REG_EBP = 6, +}; + +// +// For x86 there are four modes for the compact unwind encoding: +// UNWIND_X86_MODE_EBP_FRAME: +// EBP based frame where EBP is push on stack immediately after return address, +// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current +// EPB value, then EBP is restored by popping off the stack, and the return +// is done by popping the stack once more into the pc. +// All non-volatile registers that need to be restored must have been saved +// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4 +// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved +// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries. +// Each entry contains which register to restore. +// UNWIND_X86_MODE_STACK_IMMD: +// A "frameless" (EBP not used as frame pointer) function with a small +// constant stack size. To return, a constant (encoded in the compact +// unwind encoding) is added to the ESP. Then the return is done by +// popping the stack into the pc. +// All non-volatile registers that need to be restored must have been saved +// on the stack immediately after the return address. The stack_size/4 is +// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024). +// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT. +// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were +// saved and their order. +// UNWIND_X86_MODE_STACK_IND: +// A "frameless" (EBP not used as frame pointer) function large constant +// stack size. This case is like the previous, except the stack size is too +// large to encode in the compact unwind encoding. Instead it requires that +// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact +// encoding contains the offset to the nnnnnnnn value in the function in +// UNWIND_X86_FRAMELESS_STACK_SIZE. +// UNWIND_X86_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only DWARF unwind info for a +// function. +// +// The permutation encoding is a Lehmer code sequence encoded into a +// single variable-base number so we can encode the ordering of up to +// six registers in a 10-bit space. +// +// The following is the algorithm used to create the permutation encoding used +// with frameless stacks. It is passed the number of registers to be saved and +// an array of the register numbers saved. +// +//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6]) +//{ +// uint32_t renumregs[6]; +// for (int i=6-registerCount; i < 6; ++i) { +// int countless = 0; +// for (int j=6-registerCount; j < i; ++j) { +// if ( registers[j] < registers[i] ) +// ++countless; +// } +// renumregs[i] = registers[i] - countless -1; +// } +// uint32_t permutationEncoding = 0; +// switch ( registerCount ) { +// case 6: +// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] +// + 6*renumregs[2] + 2*renumregs[3] +// + renumregs[4]); +// break; +// case 5: +// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] +// + 6*renumregs[3] + 2*renumregs[4] +// + renumregs[5]); +// break; +// case 4: +// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] +// + 3*renumregs[4] + renumregs[5]); +// break; +// case 3: +// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] +// + renumregs[5]); +// break; +// case 2: +// permutationEncoding |= (5*renumregs[4] + renumregs[5]); +// break; +// case 1: +// permutationEncoding |= (renumregs[5]); +// break; +// } +// return permutationEncoding; +//} +// + + + + +// +// x86_64 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF +// rbp based: +// 15-bits (5*3-bits per reg) register permutation +// 8-bits for stack offset +// frameless: +// 8-bits stack size +// 3-bits stack adjust +// 3-bits register count +// 10-bits register permutation +// +enum { + UNWIND_X86_64_MODE_MASK = 0x0F000000, + UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, + UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, + UNWIND_X86_64_MODE_STACK_IND = 0x03000000, + UNWIND_X86_64_MODE_DWARF = 0x04000000, + + UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, + UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, + + UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, + UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, + UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, + UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, + + UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; + +enum { + UNWIND_X86_64_REG_NONE = 0, + UNWIND_X86_64_REG_RBX = 1, + UNWIND_X86_64_REG_R12 = 2, + UNWIND_X86_64_REG_R13 = 3, + UNWIND_X86_64_REG_R14 = 4, + UNWIND_X86_64_REG_R15 = 5, + UNWIND_X86_64_REG_RBP = 6, +}; +// +// For x86_64 there are four modes for the compact unwind encoding: +// UNWIND_X86_64_MODE_RBP_FRAME: +// RBP based frame where RBP is push on stack immediately after return address, +// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current +// EPB value, then RBP is restored by popping off the stack, and the return +// is done by popping the stack once more into the pc. +// All non-volatile registers that need to be restored must have been saved +// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8 +// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved +// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries. +// Each entry contains which register to restore. +// UNWIND_X86_64_MODE_STACK_IMMD: +// A "frameless" (RBP not used as frame pointer) function with a small +// constant stack size. To return, a constant (encoded in the compact +// unwind encoding) is added to the RSP. Then the return is done by +// popping the stack into the pc. +// All non-volatile registers that need to be restored must have been saved +// on the stack immediately after the return address. The stack_size/8 is +// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048). +// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT. +// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were +// saved and their order. +// UNWIND_X86_64_MODE_STACK_IND: +// A "frameless" (RBP not used as frame pointer) function large constant +// stack size. This case is like the previous, except the stack size is too +// large to encode in the compact unwind encoding. Instead it requires that +// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact +// encoding contains the offset to the nnnnnnnn value in the function in +// UNWIND_X86_64_FRAMELESS_STACK_SIZE. +// UNWIND_X86_64_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only DWARF unwind info for a +// function. +// + + +// ARM64 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 4=frame-based, 3=DWARF, 2=frameless +// frameless: +// 12-bits of stack size +// frame-based: +// 4-bits D reg pairs saved +// 5-bits X reg pairs saved +// DWARF: +// 24-bits offset of DWARF FDE in __eh_frame section +// +enum { + UNWIND_ARM64_MODE_MASK = 0x0F000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, + + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, + + UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, + UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; +// For arm64 there are three modes for the compact unwind encoding: +// UNWIND_ARM64_MODE_FRAME: +// This is a standard arm64 prolog where FP/LR are immediately pushed on the +// stack, then SP is copied to FP. If there are any non-volatile registers +// saved, then are copied into the stack frame in pairs in a contiguous +// range right below the saved FP/LR pair. Any subset of the five X pairs +// and four D pairs can be saved, but the memory layout must be in register +// number order. +// UNWIND_ARM64_MODE_FRAMELESS: +// A "frameless" leaf function, where FP/LR are not saved. The return address +// remains in LR throughout the function. If any non-volatile registers +// are saved, they must be pushed onto the stack before any stack space is +// allocated for local variables. The stack sized (including any saved +// non-volatile registers) divided by 16 is encoded in the bits +// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. +// UNWIND_ARM64_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the DWARF FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only DWARF unwind info for a +// function. +// + + + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Relocatable Object Files: __LD,__compact_unwind +// +//////////////////////////////////////////////////////////////////////////////// + +// +// A compiler can generated compact unwind information for a function by adding +// a "row" to the __LD,__compact_unwind section. This section has the +// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers. +// It is removed by the new linker, so never ends up in final executables. +// This section is a table, initially with one row per function (that needs +// unwind info). The table columns and some conceptual entries are: +// +// range-start pointer to start of function/range +// range-length +// compact-unwind-encoding 32-bit encoding +// personality-function or zero if no personality function +// lsda or zero if no LSDA data +// +// The length and encoding fields are 32-bits. The other are all pointer sized. +// +// In x86_64 assembly, these entry would look like: +// +// .section __LD,__compact_unwind,regular,debug +// +// #compact unwind for _foo +// .quad _foo +// .set L1,LfooEnd-_foo +// .long L1 +// .long 0x01010001 +// .quad 0 +// .quad 0 +// +// #compact unwind for _bar +// .quad _bar +// .set L2,LbarEnd-_bar +// .long L2 +// .long 0x01020011 +// .quad __gxx_personality +// .quad except_tab1 +// +// +// Notes: There is no need for any labels in the the __compact_unwind section. +// The use of the .set directive is to force the evaluation of the +// range-length at assembly time, instead of generating relocations. +// +// To support future compiler optimizations where which non-volatile registers +// are saved changes within a function (e.g. delay saving non-volatiles until +// necessary), there can by multiple lines in the __compact_unwind table for one +// function, each with a different (non-overlapping) range and each with +// different compact unwind encodings that correspond to the non-volatiles +// saved at that range of the function. +// +// If a particular function is so wacky that there is no compact unwind way +// to encode it, then the compiler can emit traditional DWARF unwind info. +// The runtime will use which ever is available. +// +// Runtime support for compact unwind encodings are only available on 10.6 +// and later. So, the compiler should not generate it when targeting pre-10.6. + + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Final Linked Images: __TEXT,__unwind_info +// +//////////////////////////////////////////////////////////////////////////////// + +// +// The __TEXT,__unwind_info section is laid out for an efficient two level lookup. +// The header of the section contains a coarse index that maps function address +// to the page (4096 byte block) containing the unwind info for that function. +// + +#define UNWIND_SECTION_VERSION 1 +struct unwind_info_section_header +{ + uint32_t version; // UNWIND_SECTION_VERSION + uint32_t commonEncodingsArraySectionOffset; + uint32_t commonEncodingsArrayCount; + uint32_t personalityArraySectionOffset; + uint32_t personalityArrayCount; + uint32_t indexSectionOffset; + uint32_t indexCount; + // compact_unwind_encoding_t[] + // uint32_t personalities[] + // unwind_info_section_header_index_entry[] + // unwind_info_section_header_lsda_index_entry[] +}; + +struct unwind_info_section_header_index_entry +{ + uint32_t functionOffset; + uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page + uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range +}; + +struct unwind_info_section_header_lsda_index_entry +{ + uint32_t functionOffset; + uint32_t lsdaOffset; +}; + +// +// There are two kinds of second level index pages: regular and compressed. +// A compressed page can hold up to 1021 entries, but it cannot be used +// if too many different encoding types are used. The regular page holds +// 511 entries. +// + +struct unwind_info_regular_second_level_entry +{ + uint32_t functionOffset; + compact_unwind_encoding_t encoding; +}; + +#define UNWIND_SECOND_LEVEL_REGULAR 2 +struct unwind_info_regular_second_level_page_header +{ + uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR + uint16_t entryPageOffset; + uint16_t entryCount; + // entry array +}; + +#define UNWIND_SECOND_LEVEL_COMPRESSED 3 +struct unwind_info_compressed_second_level_page_header +{ + uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED + uint16_t entryPageOffset; + uint16_t entryCount; + uint16_t encodingsPageOffset; + uint16_t encodingsCount; + // 32-bit entry array + // encodings array +}; + +#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) +#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF) + + + +#endif + diff --git a/libunwind/include/unwind.h b/libunwind/include/unwind.h new file mode 100644 index 0000000000..2101401337 --- /dev/null +++ b/libunwind/include/unwind.h @@ -0,0 +1,207 @@ +//===------------------------------- unwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// C++ ABI Level 1 ABI documented at: +// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +#ifndef __UNWIND_H__ +#define __UNWIND_H__ + +#include <__libunwind_config.h> + +#include +#include + +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32) +#include +#include +#endif + +#if defined(__APPLE__) +#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) +#else +#define LIBUNWIND_UNAVAIL +#endif + +typedef enum { + _URC_NO_REASON = 0, + _URC_OK = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, +#if defined(_LIBUNWIND_ARM_EHABI) + _URC_FAILURE = 9 +#endif +} _Unwind_Reason_Code; + +typedef enum { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 // gcc extension to C++ ABI +} _Unwind_Action; + +typedef struct _Unwind_Context _Unwind_Context; // opaque + +#if defined(_LIBUNWIND_ARM_EHABI) +#include "unwind_arm_ehabi.h" +#else +#include "unwind_itanium.h" +#endif + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int version, + _Unwind_Action actions, + _Unwind_Exception_Class exceptionClass, + _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context, + void* stop_parameter); + +#ifdef __cplusplus +extern "C" { +#endif + +extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); +extern uintptr_t + _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#else +extern _Unwind_Reason_Code + _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#endif + +#ifdef __USING_SJLJ_EXCEPTIONS__ +typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; +extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); +extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); +#endif + +// +// The following are semi-suppoted extensions to the C++ ABI +// + +// +// called by __cxa_rethrow(). +// +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object); +#else +extern _Unwind_Reason_Code + _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object); +#endif + +// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the +// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack +// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, + void *); +extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); + +// _Unwind_GetCFA is a gcc extension that can be called from within a +// personality handler to get the CFA (stack pointer before call) of +// current frame. +extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *); + + +// _Unwind_GetIPInfo is a gcc extension that can be called from within a +// personality handler. Similar to _Unwind_GetIP() but also returns in +// *ipBefore a non-zero value if the instruction pointer is at or before the +// instruction causing the unwind. Normally, in a function call, the IP returned +// is the return address which is after the call instruction and may be past the +// end of the function containing the call instruction. +extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore); + + +// __register_frame() is used with dynamically generated code to register the +// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point +// to its function and optional LSDA. +// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and +// 10.5 it was buggy and did not actually register the FDE with the unwinder. +// In 10.6 and later it does register properly. +extern void __register_frame(const void *fde); +extern void __deregister_frame(const void *fde); + +// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has +// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind +// info" which the runtime uses in preference to DWARF unwind info. This +// function will only work if the target function has an FDE but no compact +// unwind info. +struct dwarf_eh_bases { + uintptr_t tbase; + uintptr_t dbase; + uintptr_t func; +}; +extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); + + +// This function attempts to find the start (address of first instruction) of +// a function given an address inside the function. It only works if the +// function has an FDE (DWARF unwind info). +// This function is unimplemented on Mac OS X 10.6 and later. Instead, use +// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. +extern void *_Unwind_FindEnclosingFunction(void *pc); + +// Mac OS X does not support text-rel and data-rel addressing so these functions +// are unimplemented +extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; +extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; + +// Mac OS X 10.4 and 10.5 had implementations of these functions in +// libgcc_s.dylib, but they never worked. +/// These functions are no longer available on Mac OS X. +extern void __register_frame_info_bases(const void *fde, void *ob, void *tb, + void *db) LIBUNWIND_UNAVAIL; +extern void __register_frame_info(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table_bases(const void *fde, void *ob, + void *tb, void *db) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_table(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info_bases(const void *fde) + LIBUNWIND_UNAVAIL; + +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifndef _WIN32 +typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +typedef struct _CONTEXT CONTEXT; +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT; +#endif +// This is the common wrapper for GCC-style personality functions with SEH. +extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc, + void *frame, CONTEXT *ctx, + DISPATCHER_CONTEXT *disp, + _Unwind_Personality_Fn pers); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __UNWIND_H__ diff --git a/libunwind/include/unwind_arm_ehabi.h b/libunwind/include/unwind_arm_ehabi.h new file mode 100644 index 0000000000..747129af5e --- /dev/null +++ b/libunwind/include/unwind_arm_ehabi.h @@ -0,0 +1,169 @@ +//===------------------------------- unwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// C++ ABI Level 1 ABI documented at: +// https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst +// +//===----------------------------------------------------------------------===// + +#ifndef __ARM_EHABI_UNWIND_H__ +#define __ARM_EHABI_UNWIND_H__ + +typedef uint32_t _Unwind_State; + +static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; +static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; +static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; +static const _Unwind_State _US_ACTION_MASK = 3; +/* Undocumented flag for force unwinding. */ +static const _Unwind_State _US_FORCE_UNWIND = 8; + +typedef uint32_t _Unwind_EHT_Header; + +struct _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Control_Block; +#define _Unwind_Exception _Unwind_Control_Block /* Alias */ +typedef uint8_t _Unwind_Exception_Class[8]; + +struct _Unwind_Control_Block { + _Unwind_Exception_Class exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*); + + /* Unwinder cache, private fields for the unwinder's use */ + struct { + uint32_t reserved1; /* init reserved1 to 0, then don't touch */ + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + } unwinder_cache; + + /* Propagation barrier cache (valid after phase 1): */ + struct { + uint32_t sp; + uint32_t bitpattern[5]; + } barrier_cache; + + /* Cleanup cache (preserved over cleanup): */ + struct { + uint32_t bitpattern[4]; + } cleanup_cache; + + /* Pr cache (for pr's benefit): */ + struct { + uint32_t fnstart; /* function start address */ + _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */ + uint32_t additional; + uint32_t reserved1; + } pr_cache; + + long long int :0; /* Enforce the 8-byte alignment */ +} __attribute__((__aligned__(8))); + +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( + _Unwind_State state, _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context); + +#ifdef __cplusplus +extern "C" { +#endif + +// +// The following are the base functions documented by the C++ ABI +// +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); +#else +extern _Unwind_Reason_Code + _Unwind_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_Resume(_Unwind_Exception *exception_object); +#endif +extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); + +typedef enum { + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ + _UVRSC_WMMXD = 3, /* Intel WMMX data register */ + _UVRSC_WMMXC = 4 /* Intel WMMX control register */ +} _Unwind_VRS_RegClass; + +typedef enum { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 +} _Unwind_VRS_DataRepresentation; + +typedef enum { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 +} _Unwind_VRS_Result; + +extern void _Unwind_Complete(_Unwind_Exception* exception_object); + +extern _Unwind_VRS_Result +_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep); + +extern _Unwind_VRS_Result +_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep); + +extern _Unwind_VRS_Result +_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t discriminator, + _Unwind_VRS_DataRepresentation representation); + +#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE) +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern +#else +#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__ +#endif + +// These are de facto helper functions for ARM, which delegate the function +// calls to _Unwind_VRS_Get/Set(). These are not a part of ARM EHABI +// specification, thus these function MUST be inlined. Please don't replace +// these with the "extern" function declaration; otherwise, the program +// including this header won't be ABI compatible and will result in +// link error when we are linking the program with libgcc. + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) { + uintptr_t value = 0; + _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); + return value; +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t value) { + _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + // remove the thumb-bit before returning + return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1); +} + +_LIBUNWIND_EXPORT_UNWIND_LEVEL1 +void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) { + uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); + _Unwind_SetGR(context, 15, value | thumb_bit); +} + +#ifdef __cplusplus +} +#endif + +#endif // __ARM_EHABI_UNWIND_H__ diff --git a/libunwind/include/unwind_itanium.h b/libunwind/include/unwind_itanium.h new file mode 100644 index 0000000000..794e990dc0 --- /dev/null +++ b/libunwind/include/unwind_itanium.h @@ -0,0 +1,76 @@ +//===------------------------------- unwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// C++ ABI Level 1 ABI documented at: +// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +#ifndef __ITANIUM_UNWIND_H__ +#define __ITANIUM_UNWIND_H__ + +struct _Unwind_Context; // opaque +struct _Unwind_Exception; // forward declaration +typedef struct _Unwind_Exception _Unwind_Exception; +typedef uint64_t _Unwind_Exception_Class; + +struct _Unwind_Exception { + _Unwind_Exception_Class exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code reason, + _Unwind_Exception *exc); +#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) + uintptr_t private_[6]; +#else + uintptr_t private_1; // non-zero means forced unwind + uintptr_t private_2; // holds sp that phase1 found for phase2 to use +#endif +#if __SIZEOF_POINTER__ == 4 + // The implementation of _Unwind_Exception uses an attribute mode on the + // above fields which has the side effect of causing this whole struct to + // round up to 32 bytes in size (48 with SEH). To be more explicit, we add + // pad fields added for binary compatibility. + uint32_t reserved[3]; +#endif + // The Itanium ABI requires that _Unwind_Exception objects are "double-word + // aligned". GCC has interpreted this to mean "use the maximum useful + // alignment for the target"; so do we. +} __attribute__((__aligned__)); + +typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( + int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception *exceptionObject, struct _Unwind_Context *context); + +#ifdef __cplusplus +extern "C" { +#endif + +// +// The following are the base functions documented by the C++ ABI +// +#ifdef __USING_SJLJ_EXCEPTIONS__ +extern _Unwind_Reason_Code + _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); +#else +extern _Unwind_Reason_Code + _Unwind_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_Resume(_Unwind_Exception *exception_object); +#endif +extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); + + +extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); +extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value); +extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); +extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); + +#ifdef __cplusplus +} +#endif + +#endif // __ITANIUM_UNWIND_H__ diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp new file mode 100644 index 0000000000..171318ff63 --- /dev/null +++ b/libunwind/src/AddressSpace.hpp @@ -0,0 +1,630 @@ +//===------------------------- AddressSpace.hpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Abstracts accessing local vs remote address spaces. +// +//===----------------------------------------------------------------------===// + +#ifndef __ADDRESSSPACE_HPP__ +#define __ADDRESSSPACE_HPP__ + +#include +#include +#include +#include + +#include "libunwind.h" +#include "config.h" +#include "dwarf2.h" +#include "EHHeaderParser.hpp" +#include "Registers.hpp" + +#ifndef _LIBUNWIND_USE_DLADDR + #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32) + #define _LIBUNWIND_USE_DLADDR 1 + #else + #define _LIBUNWIND_USE_DLADDR 0 + #endif +#endif + +#if _LIBUNWIND_USE_DLADDR +#include +#if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB) +#pragma comment(lib, "dl") +#endif +#endif + +#if defined(_LIBUNWIND_ARM_EHABI) +struct EHABIIndexEntry { + uint32_t functionOffset; + uint32_t data; +}; +#endif + +#ifdef __APPLE__ + + struct dyld_unwind_sections + { + const struct mach_header* mh; + const void* dwarf_section; + uintptr_t dwarf_section_length; + const void* compact_unwind_section; + uintptr_t compact_unwind_section_length; + }; + + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); + +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. + +// The following linker script may be used to produce the necessary sections and symbols. +// Unless the --eh-frame-hdr linker option is provided, the section is not generated +// and does not take space in the output file. +// +// .eh_frame : +// { +// __eh_frame_start = .; +// KEEP(*(.eh_frame)) +// __eh_frame_end = .; +// } +// +// .eh_frame_hdr : +// { +// KEEP(*(.eh_frame_hdr)) +// } +// +// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; +// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + +extern char __eh_frame_start; +extern char __eh_frame_end; + +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) +extern char __eh_frame_hdr_start; +extern char __eh_frame_hdr_end; +#endif + +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + +// When statically linked on bare-metal, the symbols for the EH table are looked +// up without going through the dynamic loader. +extern char __exidx_start; +extern char __exidx_end; + +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + +#include +#include + +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \ + defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) + +#include + +#endif + +namespace libunwind { + +/// Used by findUnwindSections() to return info about needed sections. +struct UnwindInfoSections { +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \ + defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \ + defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + // No dso_base for SEH. + uintptr_t dso_base; +#endif +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + uintptr_t text_segment_length; +#endif +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + uintptr_t dwarf_section; + uintptr_t dwarf_section_length; +#endif +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + uintptr_t dwarf_index_section; + uintptr_t dwarf_index_section_length; +#endif +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + uintptr_t compact_unwind_section; + uintptr_t compact_unwind_section_length; +#endif +#if defined(_LIBUNWIND_ARM_EHABI) + uintptr_t arm_section; + uintptr_t arm_section_length; +#endif +}; + + +/// LocalAddressSpace is used as a template parameter to UnwindCursor when +/// unwinding a thread in the same process. The wrappers compile away, +/// making local unwinds fast. +class _LIBUNWIND_HIDDEN LocalAddressSpace { +public: + typedef uintptr_t pint_t; + typedef intptr_t sint_t; + uint8_t get8(pint_t addr) { + uint8_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint16_t get16(pint_t addr) { + uint16_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint32_t get32(pint_t addr) { + uint32_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uint64_t get64(pint_t addr) { + uint64_t val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + double getDouble(pint_t addr) { + double val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + v128 getVector(pint_t addr) { + v128 val; + memcpy(&val, (void *)addr, sizeof(val)); + return val; + } + uintptr_t getP(pint_t addr); + uint64_t getRegister(pint_t addr); + static uint64_t getULEB128(pint_t &addr, pint_t end); + static int64_t getSLEB128(pint_t &addr, pint_t end); + + pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase = 0); + bool findFunctionName(pint_t addr, char *buf, size_t bufLen, + unw_word_t *offset); + bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); + bool findOtherFDE(pint_t targetAddr, pint_t &fde); + + static LocalAddressSpace sThisAddressSpace; +}; + +inline uintptr_t LocalAddressSpace::getP(pint_t addr) { +#if __SIZEOF_POINTER__ == 8 + return get64(addr); +#else + return get32(addr); +#endif +} + +inline uint64_t LocalAddressSpace::getRegister(pint_t addr) { +#if __SIZEOF_POINTER__ == 8 || defined(__mips64) + return get64(addr); +#else + return get32(addr); +#endif +} + +/// Read a ULEB128 into a 64-bit word. +inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + uint64_t result = 0; + int bit = 0; + do { + uint64_t b; + + if (p == pend) + _LIBUNWIND_ABORT("truncated uleb128 expression"); + + b = *p & 0x7f; + + if (bit >= 64 || b << bit >> bit != b) { + _LIBUNWIND_ABORT("malformed uleb128 expression"); + } else { + result |= b << bit; + bit += 7; + } + } while (*p++ >= 0x80); + addr = (pint_t) p; + return result; +} + +/// Read a SLEB128 into a 64-bit word. +inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + int64_t result = 0; + int bit = 0; + uint8_t byte; + do { + if (p == pend) + _LIBUNWIND_ABORT("truncated sleb128 expression"); + byte = *p++; + result |= (uint64_t)(byte & 0x7f) << bit; + bit += 7; + } while (byte & 0x80); + // sign extend negative numbers + if ((byte & 0x40) != 0 && bit < 64) + result |= (-1ULL) << bit; + addr = (pint_t) p; + return result; +} + +inline LocalAddressSpace::pint_t +LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase) { + pint_t startAddr = addr; + const uint8_t *p = (uint8_t *)addr; + pint_t result; + + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_ptr: + result = getP(addr); + p += sizeof(pint_t); + addr = (pint_t) p; + break; + case DW_EH_PE_uleb128: + result = (pint_t)getULEB128(addr, end); + break; + case DW_EH_PE_udata2: + result = get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_udata4: + result = get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_udata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + case DW_EH_PE_sleb128: + result = (pint_t)getSLEB128(addr, end); + break; + case DW_EH_PE_sdata2: + // Sign extend from signed 16-bit value. + result = (pint_t)(int16_t)get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata4: + // Sign extend from signed 32-bit value. + result = (pint_t)(int32_t)get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + } + + // then add relative offset + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + result += startAddr; + break; + case DW_EH_PE_textrel: + _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); + break; + case DW_EH_PE_datarel: + // DW_EH_PE_datarel is only valid in a few places, so the parameter has a + // default value of 0, and we abort in the event that someone calls this + // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. + if (datarelBase == 0) + _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); + result += datarelBase; + break; + case DW_EH_PE_funcrel: + _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); + break; + case DW_EH_PE_aligned: + _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + break; + } + + if (encoding & DW_EH_PE_indirect) + result = getP(result); + + return result; +} + +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + +// The ElfW() macro for pointer-size independent ELF header traversal is not +// provided by on some systems (e.g., FreeBSD). On these systems the +// data structures are just called Elf_XXX. Define ElfW() locally. +#if !defined(ElfW) + #define ElfW(type) Elf_##type +#endif +#if !defined(Elf_Half) + typedef ElfW(Half) Elf_Half; +#endif +#if !defined(Elf_Phdr) + typedef ElfW(Phdr) Elf_Phdr; +#endif +#if !defined(Elf_Addr) + typedef ElfW(Addr) Elf_Addr; +#endif + +static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) { + Elf_Addr image_base = pinfo->dlpi_addr; +#if defined(__ANDROID__) && __ANDROID_API__ < 18 + if (image_base == 0) { + // Normally, an image base of 0 indicates a non-PIE executable. On + // versions of Android prior to API 18, the dynamic linker reported a + // dlpi_addr of 0 for PIE executables. Compute the true image base + // using the PT_PHDR segment. + // See https://github.com/android/ndk/issues/505. + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; + if (phdr->p_type == PT_PHDR) { + image_base = reinterpret_cast(pinfo->dlpi_phdr) - + phdr->p_vaddr; + break; + } + } + } +#endif + return image_base; +} + +struct _LIBUNWIND_HIDDEN dl_iterate_cb_data { + LocalAddressSpace *addressSpace; + UnwindInfoSections *sects; + uintptr_t targetAddr; +}; + +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) +#include "FrameHeaderCache.hpp" + +// Typically there is one cache per process, but when libunwind is built as a +// hermetic static library, then each shared object may have its own cache. +static FrameHeaderCache TheFrameHeaderCache; +#endif + +static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base, + dl_iterate_cb_data *cbdata) { + if (phdr->p_type == PT_LOAD) { + uintptr_t begin = image_base + phdr->p_vaddr; + uintptr_t end = begin + phdr->p_memsz; + if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { + cbdata->sects->dso_base = begin; + cbdata->sects->text_segment_length = phdr->p_memsz; + return true; + } + } + return false; +} + +static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base, + dl_iterate_cb_data *cbdata) { +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (phdr->p_type == PT_GNU_EH_FRAME) { + EHHeaderParser::EHHeaderInfo hdrInfo; + uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr; + cbdata->sects->dwarf_index_section = eh_frame_hdr_start; + cbdata->sects->dwarf_index_section_length = phdr->p_memsz; + if (EHHeaderParser::decodeEHHdr( + *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, + hdrInfo)) { + // .eh_frame_hdr records the start of .eh_frame, but not its size. + // Rely on a zero terminator to find the end of the section. + cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; + cbdata->sects->dwarf_section_length = UINTPTR_MAX; + return true; + } + } + return false; +#elif defined(_LIBUNWIND_ARM_EHABI) + if (phdr->p_type == PT_ARM_EXIDX) { + uintptr_t exidx_start = image_base + phdr->p_vaddr; + cbdata->sects->arm_section = exidx_start; + cbdata->sects->arm_section_length = phdr->p_memsz; + return true; + } + return false; +#else +#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI +#endif +} + +static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, + size_t pinfo_size, void *data) { + auto cbdata = static_cast(data); + if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr) + return 0; +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + if (TheFrameHeaderCache.find(pinfo, pinfo_size, data)) + return 1; +#else + // Avoid warning about unused variable. + (void)pinfo_size; +#endif + + Elf_Addr image_base = calculateImageBase(pinfo); + + // Most shared objects seen in this callback function likely don't contain the + // target address, so optimize for that. Scan for a matching PT_LOAD segment + // first and bail when it isn't found. + bool found_text = false; + for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) { + if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) { + found_text = true; + break; + } + } + if (!found_text) + return 0; + + // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate + // backward. + bool found_unwind = false; + for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) { + const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1]; + if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) { + found_unwind = true; + break; + } + } + if (!found_unwind) + return 0; + +#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + TheFrameHeaderCache.add(cbdata->sects); +#endif + return 1; +} + +#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + + +inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, + UnwindInfoSections &info) { +#ifdef __APPLE__ + dyld_unwind_sections dyldInfo; + if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { + info.dso_base = (uintptr_t)dyldInfo.mh; + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; + info.dwarf_section_length = dyldInfo.dwarf_section_length; + #endif + info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; + info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; + return true; + } +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL) + info.dso_base = 0; + // Bare metal is statically linked, so no need to ask the dynamic loader + info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start); + info.dwarf_section = (uintptr_t)(&__eh_frame_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.dwarf_section, (void *)info.dwarf_section_length); +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start); + info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p", + (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length); +#endif + if (info.dwarf_section_length) + return true; +#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL) + // Bare metal is statically linked, so no need to ask the dynamic loader + info.arm_section = (uintptr_t)(&__exidx_start); + info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p", + (void *)info.arm_section, (void *)info.arm_section_length); + if (info.arm_section && info.arm_section_length) + return true; +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32) + HMODULE mods[1024]; + HANDLE process = GetCurrentProcess(); + DWORD needed; + + if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) { + DWORD err = GetLastError(); + _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, " + "returned error %d", (int)err); + return false; + } + + for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) { + PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i]; + PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew); + PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader; + PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); + bool found_obj = false; + bool found_hdr = false; + + info.dso_base = (uintptr_t)mods[i]; + for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) { + uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i]; + uintptr_t end = begin + pish->Misc.VirtualSize; + if (!strncmp((const char *)pish->Name, ".text", + IMAGE_SIZEOF_SHORT_NAME)) { + if (targetAddr >= begin && targetAddr < end) + found_obj = true; + } else if (!strncmp((const char *)pish->Name, ".eh_frame", + IMAGE_SIZEOF_SHORT_NAME)) { + info.dwarf_section = begin; + info.dwarf_section_length = pish->Misc.VirtualSize; + found_hdr = true; + } + if (found_obj && found_hdr) + return true; + } + } + return false; +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + // Don't even bother, since Windows has functions that do all this stuff + // for us. + (void)targetAddr; + (void)info; + return true; +#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX) + int length = 0; + info.arm_section = + (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length); + info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry); + if (info.arm_section && info.arm_section_length) + return true; +#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) + dl_iterate_cb_data cb_data = {this, &info, targetAddr}; + int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data); + return static_cast(found); +#endif + + return false; +} + + +inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { + // TO DO: if OS has way to dynamically register FDEs, check that. + (void)targetAddr; + (void)fde; + return false; +} + +inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, + size_t bufLen, + unw_word_t *offset) { +#if _LIBUNWIND_USE_DLADDR + Dl_info dyldInfo; + if (dladdr((void *)addr, &dyldInfo)) { + if (dyldInfo.dli_sname != NULL) { + snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); + *offset = (addr - (pint_t) dyldInfo.dli_saddr); + return true; + } + } +#else + (void)addr; + (void)buf; + (void)bufLen; + (void)offset; +#endif + return false; +} + +} // namespace libunwind + +#endif // __ADDRESSSPACE_HPP__ diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt new file mode 100644 index 0000000000..ce3217fa80 --- /dev/null +++ b/libunwind/src/CMakeLists.txt @@ -0,0 +1,211 @@ +# Get sources + +set(LIBUNWIND_CXX_SOURCES + libunwind.cpp + Unwind-EHABI.cpp + Unwind-seh.cpp + ) +if(APPLE) + list(APPEND LIBUNWIND_CXX_SOURCES + Unwind_AppleExtras.cpp + ) +endif() + +set(LIBUNWIND_C_SOURCES + UnwindLevel1.c + UnwindLevel1-gcc-ext.c + Unwind-sjlj.c + ) +set_source_files_properties(${LIBUNWIND_C_SOURCES} + PROPERTIES + COMPILE_FLAGS "-std=c99") + +set(LIBUNWIND_ASM_SOURCES + UnwindRegistersRestore.S + UnwindRegistersSave.S + ) + +# See add_asm_sources() in compiler-rt for explanation of this workaround. +if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17)) + set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C) +endif() + +set(LIBUNWIND_HEADERS + AddressSpace.hpp + assembly.h + CompactUnwinder.hpp + cet_unwind.h + config.h + dwarf2.h + DwarfInstructions.hpp + DwarfParser.hpp + EHHeaderParser.hpp + FrameHeaderCache.hpp + libunwind_ext.h + Registers.hpp + RWMutex.hpp + Unwind-EHABI.h + UnwindCursor.hpp + ../include/libunwind.h + ../include/unwind.h + ../include/unwind_itanium.h + ../include/unwind_arm_ehabi.h + ) +if(APPLE) + list(APPEND LIBUNWIND_HEADERS + ../include/mach-o/compact_unwind_encoding.h + ) +endif() + +if (MSVC_IDE) + # Force them all into the headers dir on MSVC, otherwise they end up at + # project scope because they don't have extensions. + source_group("Header Files" FILES ${LIBUNWIND_HEADERS}) +endif() + +set(LIBUNWIND_SOURCES + ${LIBUNWIND_CXX_SOURCES} + ${LIBUNWIND_C_SOURCES} + ${LIBUNWIND_ASM_SOURCES}) + +# Generate library list. +add_library_flags_if(LIBUNWIND_HAS_C_LIB c) +if (LIBUNWIND_USE_COMPILER_RT) + add_library_flags("${LIBUNWIND_BUILTINS_LIBRARY}") +else() + add_library_flags_if(LIBUNWIND_HAS_GCC_S_LIB gcc_s) + add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc) +endif() +add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl) +if (LIBUNWIND_ENABLE_THREADS) + add_library_flags_if(LIBUNWIND_HAS_PTHREAD_LIB pthread) + add_compile_flags_if(LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1) +endif() + +# Setup flags. +if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG) + add_link_flags_if_supported(-nostdlib++) +else() + add_link_flags_if_supported(-nodefaultlibs) +endif() + +# MINGW_LIBRARIES is defined in config-ix.cmake +add_library_flags_if(MINGW "${MINGW_LIBRARIES}") + +if (LIBUNWIND_ENABLE_SHARED AND + NOT (LIBUNWIND_SUPPORTS_FNO_EXCEPTIONS_FLAG AND + LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG)) + message(FATAL_ERROR + "Compiler doesn't support generation of unwind tables if exception " + "support is disabled. Building libunwind DSO with runtime dependency " + "on C++ ABI library is not supported.") +endif() + +if (APPLE) + add_compile_flags("-U__STRICT_ANSI__") + add_link_flags("-compatibility_version 1" "-install_name /usr/lib/libunwind.1.dylib") + + if (CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6") + add_link_flags("-current_version ${LIBUNWIND_VERSION}" "/usr/lib/libSystem.B.dylib") + endif () +endif () + +string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_C_FLAGS "${LIBUNWIND_C_FLAGS}") +string(REPLACE ";" " " LIBUNWIND_LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}") + +set_property(SOURCE ${LIBUNWIND_CXX_SOURCES} + APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_CXX_FLAGS}") +set_property(SOURCE ${LIBUNWIND_C_SOURCES} + APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_C_FLAGS}") + +# NOTE: avoid implicit dependencies on C++ runtimes. libunwind uses C++ for +# ease, but does not rely on C++ at runtime. +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") + +# Build the shared library. +if (LIBUNWIND_ENABLE_SHARED) + add_library(unwind_shared SHARED ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) + if(CMAKE_C_COMPILER_ID STREQUAL MSVC) + target_compile_options(unwind_shared PRIVATE /GR-) + else() + target_compile_options(unwind_shared PRIVATE -fno-rtti) + endif() + target_link_libraries(unwind_shared PRIVATE ${LIBUNWIND_LIBRARIES}) + set_target_properties(unwind_shared + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}" + LINKER_LANGUAGE C + OUTPUT_NAME "unwind" + VERSION "1.0" + SOVERSION "1" + POSITION_INDEPENDENT_CODE ON + ) + list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_shared") + if (LIBUNWIND_INSTALL_SHARED_LIBRARY) + list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_shared") + endif() +endif() + +# Build the static library. +if (LIBUNWIND_ENABLE_STATIC) + add_library(unwind_static STATIC ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS}) + if(CMAKE_C_COMPILER_ID STREQUAL MSVC) + target_compile_options(unwind_static PRIVATE /GR-) + else() + target_compile_options(unwind_static PRIVATE -fno-rtti) + endif() + target_link_libraries(unwind_static PRIVATE ${LIBUNWIND_LIBRARIES}) + set_target_properties(unwind_static + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}" + LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}" + LINKER_LANGUAGE C + OUTPUT_NAME "unwind" + POSITION_INDEPENDENT_CODE ON + ) + + if(LIBUNWIND_HIDE_SYMBOLS) + append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility=hidden) + append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden) + target_compile_options(unwind_static PRIVATE ${UNWIND_STATIC_LIBRARY_FLAGS}) + target_compile_definitions(unwind_static PRIVATE _LIBUNWIND_HIDE_SYMBOLS) + endif() + + list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_static") + if (LIBUNWIND_INSTALL_STATIC_LIBRARY) + list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_static") + endif() +endif() + +# Add a meta-target for both libraries. +add_custom_target(unwind DEPENDS ${LIBUNWIND_BUILD_TARGETS}) + +if (LIBUNWIND_INSTALL_LIBRARY) + install(TARGETS ${LIBUNWIND_INSTALL_TARGETS} + LIBRARY DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind + ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind + RUNTIME DESTINATION ${LIBUNWIND_INSTALL_RUNTIME_DIR} COMPONENT unwind) +endif() + +if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY) + add_custom_target(install-unwind + DEPENDS unwind + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=unwind + -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") + add_custom_target(install-unwind-stripped + DEPENDS unwind + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=unwind + -DCMAKE_INSTALL_DO_STRIP=1 + -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake") +endif() diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp new file mode 100644 index 0000000000..312bfbb2c7 --- /dev/null +++ b/libunwind/src/CompactUnwinder.hpp @@ -0,0 +1,697 @@ +//===-------------------------- CompactUnwinder.hpp -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Does runtime stack unwinding using compact unwind encodings. +// +//===----------------------------------------------------------------------===// + +#ifndef __COMPACT_UNWINDER_HPP__ +#define __COMPACT_UNWINDER_HPP__ + +#include +#include + +#include +#include + +#include "Registers.hpp" + +#define EXTRACT_BITS(value, mask) \ + ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) + +namespace libunwind { + +#if defined(_LIBUNWIND_TARGET_I386) +/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86 register set +template +class CompactUnwinder_x86 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t info, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + +private: + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86 ®isters); + static void framelessUnwind(A &addressSpace, + typename A::pint_t returnAddressLocation, + Registers_x86 ®isters); + static int + stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize); +}; + +template +int CompactUnwinder_x86::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + switch (compactEncoding & UNWIND_X86_MODE_MASK) { + case UNWIND_X86_MODE_EBP_FRAME: + return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); + + uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " + "function starting at 0x%X", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 4; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 4 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EBP: + registers.setEBP(addressSpace.get32(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%X", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; +} + + +template +void CompactUnwinder_x86::frameUnwind(A &addressSpace, + Registers_x86 ®isters) { + typename A::pint_t bp = registers.getEBP(); + // ebp points to old ebp + registers.setEBP(addressSpace.get32(bp)); + // old esp is ebp less saved ebp and return address + registers.setSP((uint32_t)bp + 8); + // pop return address into eip + registers.setIP(addressSpace.get32(bp + 4)); +} + +template +void CompactUnwinder_x86::framelessUnwind( + A &addressSpace, typename A::pint_t returnAddressLocation, + Registers_x86 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get32(returnAddressLocation)); + // old esp is before return address + registers.setSP((uint32_t)returnAddressLocation + 4); +} +#endif // _LIBUNWIND_TARGET_I386 + + +#if defined(_LIBUNWIND_TARGET_X86_64) +/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86_64 register set +template +class CompactUnwinder_x86_64 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + +private: + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); + static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, + Registers_x86_64 ®isters); + static int + stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); +}; + +template +int CompactUnwinder_x86_64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { + case UNWIND_X86_64_MODE_RBP_FRAME: + return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_64_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_64_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); + + uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_64_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " + "function starting at 0x%llX", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 8; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 8 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_RBP: + registers.setRBP(addressSpace.get64(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%llX", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; +} + + +template +void CompactUnwinder_x86_64::frameUnwind(A &addressSpace, + Registers_x86_64 ®isters) { + uint64_t rbp = registers.getRBP(); + // ebp points to old ebp + registers.setRBP(addressSpace.get64(rbp)); + // old esp is ebp less saved ebp and return address + registers.setSP(rbp + 16); + // pop return address into eip + registers.setIP(addressSpace.get64(rbp + 8)); +} + +template +void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, + uint64_t returnAddressLocation, + Registers_x86_64 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get64(returnAddressLocation)); + // old esp is before return address + registers.setSP(returnAddressLocation + 8); +} +#endif // _LIBUNWIND_TARGET_X86_64 + + + +#if defined(_LIBUNWIND_TARGET_AARCH64) +/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_arm64 register set +template +class CompactUnwinder_arm64 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm64 ®isters); + +private: + typename A::pint_t pint_t; + + static int + stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_arm64 ®isters); +}; + +template +int CompactUnwinder_arm64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_arm64 ®isters) { + switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { + case UNWIND_ARM64_MODE_FRAME: + return stepWithCompactEncodingFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_ARM64_MODE_FRAMELESS: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + Registers_arm64 ®isters) { + uint32_t stackSize = + 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); + + uint64_t savedRegisterLoc = registers.getSP() + stackSize; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + // subtract stack size off of sp + registers.setSP(savedRegisterLoc); + + // set pc to be value in lr + registers.setIP(registers.getRegister(UNW_AARCH64_LR)); + + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrame( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + Registers_arm64 ®isters) { + uint64_t savedRegisterLoc = registers.getFP() - 8; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_AARCH64_V14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_AARCH64_V15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + uint64_t fp = registers.getFP(); + // fp points to old fp + registers.setFP(addressSpace.get64(fp)); + // old sp is fp less saved fp and lr + registers.setSP(fp + 16); + // pop return address into pc + registers.setIP(addressSpace.get64(fp + 8)); + + return UNW_STEP_SUCCESS; +} +#endif // _LIBUNWIND_TARGET_AARCH64 + + +} // namespace libunwind + +#endif // __COMPACT_UNWINDER_HPP__ diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp new file mode 100644 index 0000000000..b58c51bb7a --- /dev/null +++ b/libunwind/src/DwarfInstructions.hpp @@ -0,0 +1,838 @@ +//===-------------------------- DwarfInstructions.hpp ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Processor specific interpretation of DWARF unwind info. +// +//===----------------------------------------------------------------------===// + +#ifndef __DWARF_INSTRUCTIONS_HPP__ +#define __DWARF_INSTRUCTIONS_HPP__ + +#include +#include +#include + +#include "dwarf2.h" +#include "Registers.hpp" +#include "DwarfParser.hpp" +#include "config.h" + + +namespace libunwind { + + +/// DwarfInstructions maps abtract DWARF unwind instructions to a particular +/// architecture +template +class DwarfInstructions { +public: + typedef typename A::pint_t pint_t; + typedef typename A::sint_t sint_t; + + static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, + R ®isters, bool &isSignalFrame); + +private: + + enum { + DW_X86_64_RET_ADDR = 16 + }; + + enum { + DW_X86_RET_ADDR = 8 + }; + + typedef typename CFI_Parser::RegisterLocation RegisterLocation; + typedef typename CFI_Parser::PrologInfo PrologInfo; + typedef typename CFI_Parser::FDE_Info FDE_Info; + typedef typename CFI_Parser::CIE_Info CIE_Info; + + static pint_t evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue); + static pint_t getSavedRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static double getSavedFloatRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + + static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, + const R ®isters) { + if (prolog.cfaRegister != 0) + return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + + prolog.cfaRegisterOffset); + if (prolog.cfaExpression != 0) + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, + registers, 0); + assert(0 && "getCFA(): unknown location"); + __builtin_unreachable(); + } +}; + + +template +typename A::pint_t DwarfInstructions::getSavedRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return (pint_t)addressSpace.getRegister(evaluateExpression( + (pint_t)savedReg.value, addressSpace, registers, cfa)); + + case CFI_Parser::kRegisterIsExpression: + return evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa); + + case CFI_Parser::kRegisterInRegister: + return registers.getRegister((int)savedReg.value); + case CFI_Parser::kRegisterUndefined: + return 0; + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for register"); +} + +template +double DwarfInstructions::getSavedFloatRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getDouble(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getDouble( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + case CFI_Parser::kRegisterUndefined: + return 0.0; + case CFI_Parser::kRegisterInRegister: +#ifndef _LIBUNWIND_TARGET_ARM + return registers.getFloatRegister((int)savedReg.value); +#endif + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for float register"); +} + +template +v128 DwarfInstructions::getSavedVectorRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getVector(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getVector( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterUndefined: + case CFI_Parser::kRegisterOffsetFromCFA: + case CFI_Parser::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for vector register"); +} + +template +int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, + pint_t fdeStart, R ®isters, + bool &isSignalFrame) { + FDE_Info fdeInfo; + CIE_Info cieInfo; + if (CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, + &cieInfo) == NULL) { + PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &prolog)) { + // get pointer to cfa (architecture specific) + pint_t cfa = getCFA(addressSpace, prolog, registers); + + // restore registers that DWARF says were saved + R newRegisters = registers; + + // Typically, the CFA is the stack pointer at the call site in + // the previous frame. However, there are scenarios in which this is not + // true. For example, if we switched to a new stack. In that case, the + // value of the previous SP might be indicated by a CFI directive. + // + // We set the SP here to the CFA, allowing for it to be overridden + // by a CFI directive later on. + newRegisters.setSP(cfa); + + pint_t returnAddress = 0; + const int lastReg = R::lastDwarfRegNum(); + assert(static_cast(CFI_Parser::kMaxRegisterNumber) >= lastReg && + "register range too large"); + assert(lastReg >= (int)cieInfo.returnAddressRegister && + "register range does not contain return address register"); + for (int i = 0; i <= lastReg; ++i) { + if (prolog.savedRegisters[i].location != + CFI_Parser::kRegisterUnused) { + if (registers.validFloatRegister(i)) + newRegisters.setFloatRegister( + i, getSavedFloatRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (registers.validVectorRegister(i)) + newRegisters.setVectorRegister( + i, getSavedVectorRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (i == (int)cieInfo.returnAddressRegister) + returnAddress = getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i]); + else if (registers.validRegister(i)) + newRegisters.setRegister( + i, getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else + return UNW_EBADREG; + } else if (i == (int)cieInfo.returnAddressRegister) { + // Leaf function keeps the return address in register and there is no + // explicit intructions how to restore it. + returnAddress = registers.getRegister(cieInfo.returnAddressRegister); + } + } + + isSignalFrame = cieInfo.isSignalFrame; + +#if defined(_LIBUNWIND_TARGET_AARCH64) + // If the target is aarch64 then the return address may have been signed + // using the v8.3 pointer authentication extensions. The original + // return address needs to be authenticated before the return address is + // restored. autia1716 is used instead of autia as autia1716 assembles + // to a NOP on pre-v8.3a architectures. + if ((R::getArch() == REGISTERS_ARM64) && + prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value && + returnAddress != 0) { +#if !defined(_LIBUNWIND_IS_NATIVE_ONLY) + return UNW_ECROSSRASIGNING; +#else + register unsigned long long x17 __asm("x17") = returnAddress; + register unsigned long long x16 __asm("x16") = cfa; + + // These are the autia1716/autib1716 instructions. The hint instructions + // are used here as gcc does not assemble autia1716/autib1716 for pre + // armv8.3a targets. + if (cieInfo.addressesSignedWithBKey) + asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716 + else + asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716 + returnAddress = x17; +#endif + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + if (R::getArch() == REGISTERS_SPARC) { + // Skip call site instruction and delay slot + returnAddress += 8; + // Skip unimp instruction if function returns a struct + if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0) + returnAddress += 4; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) +#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1) +#define PPC64_ELFV1_R2_OFFSET 40 +#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1) +#define PPC64_ELFV2_R2_OFFSET 24 + // If the instruction at return address is a TOC (r2) restore, + // then r2 was saved and needs to be restored. + // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24, + // while in ELFv1 ABI it is saved at SP + 40. + if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) { + pint_t sp = newRegisters.getRegister(UNW_REG_SP); + pint_t r2 = 0; + switch (addressSpace.get32(returnAddress)) { + case PPC64_ELFV1_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET); + break; + case PPC64_ELFV2_R2_LOAD_INST_ENCODING: + r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET); + break; + } + if (r2) + newRegisters.setRegister(UNW_PPC64_R2, r2); + } +#endif + + // Return address is address after call site instruction, so setting IP to + // that does simualates a return. + newRegisters.setIP(returnAddress); + + // Simulate the step by replacing the register set with the new ones. + registers = newRegisters; + + return UNW_STEP_SUCCESS; + } + } + return UNW_EBADFRAME; +} + +template +typename A::pint_t +DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue) { + const bool log = false; + pint_t p = expression; + pint_t expressionEnd = expression + 20; // temp, until len read + pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); + expressionEnd = p + length; + if (log) + fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n", + (uint64_t)length); + pint_t stack[100]; + pint_t *sp = stack; + *(++sp) = initialStackValue; + + while (p < expressionEnd) { + if (log) { + for (pint_t *t = sp; t > stack; --t) { + fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t)); + } + } + uint8_t opcode = addressSpace.get8(p++); + sint_t svalue, svalue2; + pint_t value; + uint32_t reg; + switch (opcode) { + case DW_OP_addr: + // push immediate address sized value + value = addressSpace.getP(p); + p += sizeof(pint_t); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_deref: + // pop stack, dereference, push result + value = *sp--; + *(++sp) = addressSpace.getP(value); + if (log) + fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const1u: + // push immediate 1 byte value + value = addressSpace.get8(p); + p += 1; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const1s: + // push immediate 1 byte signed value + svalue = (int8_t) addressSpace.get8(p); + p += 1; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const2u: + // push immediate 2 byte value + value = addressSpace.get16(p); + p += 2; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const2s: + // push immediate 2 byte signed value + svalue = (int16_t) addressSpace.get16(p); + p += 2; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const4u: + // push immediate 4 byte value + value = addressSpace.get32(p); + p += 4; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const4s: + // push immediate 4 byte signed value + svalue = (int32_t)addressSpace.get32(p); + p += 4; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_const8u: + // push immediate 8 byte value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_const8s: + // push immediate 8 byte signed value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_constu: + // push immediate ULEB128 value + value = (pint_t)addressSpace.getULEB128(p, expressionEnd); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_consts: + // push immediate SLEB128 value + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue); + break; + + case DW_OP_dup: + // push top of stack + value = *sp; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate top of stack\n"); + break; + + case DW_OP_drop: + // pop + --sp; + if (log) + fprintf(stderr, "pop top of stack\n"); + break; + + case DW_OP_over: + // dup second + value = sp[-1]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate second in stack\n"); + break; + + case DW_OP_pick: + // pick from + reg = addressSpace.get8(p); + p += 1; + value = sp[-(int)reg]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate %d in stack\n", reg); + break; + + case DW_OP_swap: + // swap top two + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = value; + if (log) + fprintf(stderr, "swap top of stack\n"); + break; + + case DW_OP_rot: + // rotate top three + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = value; + if (log) + fprintf(stderr, "rotate top three of stack\n"); + break; + + case DW_OP_xderef: + // pop stack, dereference, push result + value = *sp--; + *sp = *((pint_t*)value); + if (log) + fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_abs: + svalue = (sint_t)*sp; + if (svalue < 0) + *sp = (pint_t)(-svalue); + if (log) + fprintf(stderr, "abs\n"); + break; + + case DW_OP_and: + value = *sp--; + *sp &= value; + if (log) + fprintf(stderr, "and\n"); + break; + + case DW_OP_div: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 / svalue); + if (log) + fprintf(stderr, "div\n"); + break; + + case DW_OP_minus: + value = *sp--; + *sp = *sp - value; + if (log) + fprintf(stderr, "minus\n"); + break; + + case DW_OP_mod: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 % svalue); + if (log) + fprintf(stderr, "module\n"); + break; + + case DW_OP_mul: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 * svalue); + if (log) + fprintf(stderr, "mul\n"); + break; + + case DW_OP_neg: + *sp = 0 - *sp; + if (log) + fprintf(stderr, "neg\n"); + break; + + case DW_OP_not: + svalue = (sint_t)(*sp); + *sp = (pint_t)(~svalue); + if (log) + fprintf(stderr, "not\n"); + break; + + case DW_OP_or: + value = *sp--; + *sp |= value; + if (log) + fprintf(stderr, "or\n"); + break; + + case DW_OP_plus: + value = *sp--; + *sp += value; + if (log) + fprintf(stderr, "plus\n"); + break; + + case DW_OP_plus_uconst: + // pop stack, add uelb128 constant, push result + *sp += static_cast(addressSpace.getULEB128(p, expressionEnd)); + if (log) + fprintf(stderr, "add constant\n"); + break; + + case DW_OP_shl: + value = *sp--; + *sp = *sp << value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shr: + value = *sp--; + *sp = *sp >> value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shra: + value = *sp--; + svalue = (sint_t)*sp; + *sp = (pint_t)(svalue >> value); + if (log) + fprintf(stderr, "shift left arithmetric\n"); + break; + + case DW_OP_xor: + value = *sp--; + *sp ^= value; + if (log) + fprintf(stderr, "xor\n"); + break; + + case DW_OP_skip: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue); + break; + + case DW_OP_bra: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + if (*sp--) + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue); + break; + + case DW_OP_eq: + value = *sp--; + *sp = (*sp == value); + if (log) + fprintf(stderr, "eq\n"); + break; + + case DW_OP_ge: + value = *sp--; + *sp = (*sp >= value); + if (log) + fprintf(stderr, "ge\n"); + break; + + case DW_OP_gt: + value = *sp--; + *sp = (*sp > value); + if (log) + fprintf(stderr, "gt\n"); + break; + + case DW_OP_le: + value = *sp--; + *sp = (*sp <= value); + if (log) + fprintf(stderr, "le\n"); + break; + + case DW_OP_lt: + value = *sp--; + *sp = (*sp < value); + if (log) + fprintf(stderr, "lt\n"); + break; + + case DW_OP_ne: + value = *sp--; + *sp = (*sp != value); + if (log) + fprintf(stderr, "ne\n"); + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + value = static_cast(opcode - DW_OP_lit0); + *(++sp) = value; + if (log) + fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + reg = static_cast(opcode - DW_OP_reg0); + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d\n", reg); + break; + + case DW_OP_regx: + reg = static_cast(addressSpace.getULEB128(p, expressionEnd)); + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + reg = static_cast(opcode - DW_OP_breg0); + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += static_cast(registers.getRegister((int)reg)); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_bregx: + reg = static_cast(addressSpace.getULEB128(p, expressionEnd)); + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += static_cast(registers.getRegister((int)reg)); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue); + break; + + case DW_OP_fbreg: + _LIBUNWIND_ABORT("DW_OP_fbreg not implemented"); + break; + + case DW_OP_piece: + _LIBUNWIND_ABORT("DW_OP_piece not implemented"); + break; + + case DW_OP_deref_size: + // pop stack, dereference, push result + value = *sp--; + switch (addressSpace.get8(p++)) { + case 1: + value = addressSpace.get8(value); + break; + case 2: + value = addressSpace.get16(value); + break; + case 4: + value = addressSpace.get32(value); + break; + case 8: + value = (pint_t)addressSpace.get64(value); + break; + default: + _LIBUNWIND_ABORT("DW_OP_deref_size with bad size"); + } + *(++sp) = value; + if (log) + fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value); + break; + + case DW_OP_xderef_size: + case DW_OP_nop: + case DW_OP_push_object_addres: + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_call_ref: + default: + _LIBUNWIND_ABORT("DWARF opcode not implemented"); + } + + } + if (log) + fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp); + return *sp; +} + + + +} // namespace libunwind + +#endif // __DWARF_INSTRUCTIONS_HPP__ diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp new file mode 100644 index 0000000000..2a7155ba9e --- /dev/null +++ b/libunwind/src/DwarfParser.hpp @@ -0,0 +1,813 @@ +//===--------------------------- DwarfParser.hpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Parses DWARF CFIs (FDEs and CIEs). +// +//===----------------------------------------------------------------------===// + +#ifndef __DWARF_PARSER_HPP__ +#define __DWARF_PARSER_HPP__ + +#include +#include +#include +#include + +#include "libunwind.h" +#include "dwarf2.h" +#include "Registers.hpp" + +#include "config.h" + +namespace libunwind { + +/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. +/// See DWARF Spec for details: +/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +/// +template +class CFI_Parser { +public: + typedef typename A::pint_t pint_t; + + /// Information encoded in a CIE (Common Information Entry) + struct CIE_Info { + pint_t cieStart; + pint_t cieLength; + pint_t cieInstructions; + uint8_t pointerEncoding; + uint8_t lsdaEncoding; + uint8_t personalityEncoding; + uint8_t personalityOffsetInCIE; + pint_t personality; + uint32_t codeAlignFactor; + int dataAlignFactor; + bool isSignalFrame; + bool fdesHaveAugmentationData; + uint8_t returnAddressRegister; +#if defined(_LIBUNWIND_TARGET_AARCH64) + bool addressesSignedWithBKey; +#endif + }; + + /// Information about an FDE (Frame Description Entry) + struct FDE_Info { + pint_t fdeStart; + pint_t fdeLength; + pint_t fdeInstructions; + pint_t pcStart; + pint_t pcEnd; + pint_t lsda; + }; + + enum { + kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER + }; + enum RegisterSavedWhere { + kRegisterUnused, + kRegisterUndefined, + kRegisterInCFA, + kRegisterOffsetFromCFA, + kRegisterInRegister, + kRegisterAtExpression, + kRegisterIsExpression + }; + struct RegisterLocation { + RegisterSavedWhere location; + bool initialStateSaved; + int64_t value; + }; + /// Information about a frame layout and registers saved determined + /// by "running" the DWARF FDE "instructions" + struct PrologInfo { + uint32_t cfaRegister; + int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset + int64_t cfaExpression; // CFA = expression + uint32_t spExtraArgSize; + RegisterLocation savedRegisters[kMaxRegisterNumber + 1]; + enum class InitializeTime { kLazy, kNormal }; + + // When saving registers, this data structure is lazily initialized. + PrologInfo(InitializeTime IT = InitializeTime::kNormal) { + if (IT == InitializeTime::kNormal) + memset(this, 0, sizeof(*this)); + } + void checkSaveRegister(uint64_t reg, PrologInfo &initialState) { + if (!savedRegisters[reg].initialStateSaved) { + initialState.savedRegisters[reg] = savedRegisters[reg]; + savedRegisters[reg].initialStateSaved = true; + } + } + void setRegister(uint64_t reg, RegisterSavedWhere newLocation, + int64_t newValue, PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].location = newLocation; + savedRegisters[reg].value = newValue; + } + void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation, + PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].location = newLocation; + } + void setRegisterValue(uint64_t reg, int64_t newValue, + PrologInfo &initialState) { + checkSaveRegister(reg, initialState); + savedRegisters[reg].value = newValue; + } + void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) { + if (savedRegisters[reg].initialStateSaved) + savedRegisters[reg] = initialState.savedRegisters[reg]; + // else the register still holds its initial state + } + }; + + struct PrologInfoStackEntry { + PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) + : next(n), info(i) {} + PrologInfoStackEntry *next; + PrologInfo info; + }; + + struct RememberStack { + PrologInfoStackEntry *entry; + RememberStack() : entry(nullptr) {} + ~RememberStack() { +#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED) + // Clean up rememberStack. Even in the case where every + // DW_CFA_remember_state is paired with a DW_CFA_restore_state, + // parseInstructions can skip restore opcodes if it reaches the target PC + // and stops interpreting, so we have to make sure we don't leak memory. + while (entry) { + PrologInfoStackEntry *next = entry->next; + _LIBUNWIND_REMEMBER_FREE(entry); + entry = next; + } +#endif + } + }; + + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, + CIE_Info *cieInfo); + static const char *decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo); + static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + int arch, PrologInfo *results); + + static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); +}; + +/// Parse a FDE into a CIE_Info and an FDE_Info +template +const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + pint_t p = fdeStart; + pint_t cfiLength = (pint_t)addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return "FDE has zero length"; // zero terminator + uint32_t ciePointer = addressSpace.get32(p); + if (ciePointer == 0) + return "FDE is really a CIE"; // this is a CIE not an FDE + pint_t nextCFI = p + cfiLength; + pint_t cieStart = p - ciePointer; + const char *err = parseCIE(addressSpace, cieStart, cieInfo); + if (err != NULL) + return err; + p += 4; + // Parse pc begin and range. + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // Parse rest of info. + fdeInfo->lsda = 0; + // Check for augmentation length. + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { + // Peek at value (without indirection). Zero means no LSDA. + pint_t lsdaStart = p; + if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != + 0) { + // Reset pointer and re-parse LSDA address. + p = lsdaStart; + fdeInfo->lsda = + addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = fdeStart; + fdeInfo->fdeLength = nextCFI - fdeStart; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return NULL; // success +} + +/// Scan an eh_frame section to find an FDE for a pc +template +bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uintptr_t sectionLength, pint_t fdeHint, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); + pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; + const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX) + ? static_cast(-1) + : (ehSectionStart + sectionLength); + while (p < ehSectionEnd) { + pint_t currentCFI = p; + //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); + pint_t cfiLength = addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return false; // zero terminator + uint32_t id = addressSpace.get32(p); + if (id == 0) { + // Skip over CIEs. + p += cfiLength; + } else { + // Process FDE to see if it covers pc. + pint_t nextCFI = p + cfiLength; + uint32_t ciePointer = addressSpace.get32(p); + pint_t cieStart = p - ciePointer; + // Validate pointer to CIE is within section. + if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { + if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { + p += 4; + // Parse pc begin and range. + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = addressSpace.getEncodedP( + p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // Test if pc is within the function this FDE covers. + if ((pcStart < pc) && (pc <= pcStart + pcRange)) { + // parse rest of info + fdeInfo->lsda = 0; + // check for augmentation length + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != DW_EH_PE_omit) { + // Peek at value (without indirection). Zero means no LSDA. + pint_t lsdaStart = p; + if (addressSpace.getEncodedP( + p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { + // Reset pointer and re-parse LSDA address. + p = lsdaStart; + fdeInfo->lsda = addressSpace + .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = currentCFI; + fdeInfo->fdeLength = nextCFI - currentCFI; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return true; + } else { + // pc is not in begin/range, skip this FDE + } + } else { + // Malformed CIE, now augmentation describing pc range encoding. + } + } else { + // malformed FDE. CIE is bad + } + p = nextCFI; + } + } + return false; +} + +/// Extract info from a CIE +template +const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, + CIE_Info *cieInfo) { + cieInfo->pointerEncoding = 0; + cieInfo->lsdaEncoding = DW_EH_PE_omit; + cieInfo->personalityEncoding = 0; + cieInfo->personalityOffsetInCIE = 0; + cieInfo->personality = 0; + cieInfo->codeAlignFactor = 0; + cieInfo->dataAlignFactor = 0; + cieInfo->isSignalFrame = false; + cieInfo->fdesHaveAugmentationData = false; +#if defined(_LIBUNWIND_TARGET_AARCH64) + cieInfo->addressesSignedWithBKey = false; +#endif + cieInfo->cieStart = cie; + pint_t p = cie; + pint_t cieLength = (pint_t)addressSpace.get32(p); + p += 4; + pint_t cieContentEnd = p + cieLength; + if (cieLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cieLength = (pint_t)addressSpace.get64(p); + p += 8; + cieContentEnd = p + cieLength; + } + if (cieLength == 0) + return NULL; + // CIE ID is always 0 + if (addressSpace.get32(p) != 0) + return "CIE ID is not zero"; + p += 4; + // Version is always 1 or 3 + uint8_t version = addressSpace.get8(p); + if ((version != 1) && (version != 3)) + return "CIE version is not 1 or 3"; + ++p; + // save start of augmentation string and find end + pint_t strStart = p; + while (addressSpace.get8(p) != 0) + ++p; + ++p; + // parse code aligment factor + cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); + // parse data alignment factor + cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); + // parse return address register + uint64_t raReg = (version == 1) ? addressSpace.get8(p++) + : addressSpace.getULEB128(p, cieContentEnd); + assert(raReg < 255 && "return address register too large"); + cieInfo->returnAddressRegister = (uint8_t)raReg; + // parse augmentation data based on augmentation string + const char *result = NULL; + if (addressSpace.get8(strStart) == 'z') { + // parse augmentation data length + addressSpace.getULEB128(p, cieContentEnd); + for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { + switch (addressSpace.get8(s)) { + case 'z': + cieInfo->fdesHaveAugmentationData = true; + break; + case 'P': + cieInfo->personalityEncoding = addressSpace.get8(p); + ++p; + cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); + cieInfo->personality = addressSpace + .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); + break; + case 'L': + cieInfo->lsdaEncoding = addressSpace.get8(p); + ++p; + break; + case 'R': + cieInfo->pointerEncoding = addressSpace.get8(p); + ++p; + break; + case 'S': + cieInfo->isSignalFrame = true; + break; +#if defined(_LIBUNWIND_TARGET_AARCH64) + case 'B': + cieInfo->addressesSignedWithBKey = true; + break; +#endif + default: + // ignore unknown letters + break; + } + } + } + cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; + cieInfo->cieInstructions = p; + return result; +} + + +/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE +template +bool CFI_Parser::parseFDEInstructions(A &addressSpace, + const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + int arch, PrologInfo *results) { + // Alloca is used for the allocation of the rememberStack entries. It removes + // the dependency on new/malloc but the below for loop can not be refactored + // into functions. Entry could be saved during the processing of a CIE and + // restored by an FDE. + RememberStack rememberStack; + + struct ParseInfo { + pint_t instructions; + pint_t instructionsEnd; + pint_t pcoffset; + }; + + ParseInfo parseInfoArray[] = { + {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, + (pint_t)(-1)}, + {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, + upToPC - fdeInfo.pcStart}}; + + for (const auto &info : parseInfoArray) { + pint_t p = info.instructions; + pint_t instructionsEnd = info.instructionsEnd; + pint_t pcoffset = info.pcoffset; + pint_t codeOffset = 0; + + // initialState initialized as registers in results are modified. Use + // PrologInfo accessor functions to avoid reading uninitialized data. + PrologInfo initialState(PrologInfo::InitializeTime::kLazy); + + _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64 + ")\n", + static_cast(instructionsEnd)); + + // see DWARF Spec, section 6.4.2 for details on unwind opcodes + while ((p < instructionsEnd) && (codeOffset < pcoffset)) { + uint64_t reg; + uint64_t reg2; + int64_t offset; + uint64_t length; + uint8_t opcode = addressSpace.get8(p); + uint8_t operand; + + ++p; + switch (opcode) { + case DW_CFA_nop: + _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n"); + break; + case DW_CFA_set_loc: + codeOffset = addressSpace.getEncodedP(p, instructionsEnd, + cieInfo.pointerEncoding); + _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n"); + break; + case DW_CFA_advance_loc1: + codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); + p += 1; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_advance_loc2: + codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); + p += 2; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_advance_loc4: + codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); + p += 4; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_restore_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_restore_extended DWARF unwind, reg too big"); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", + reg); + break; + case DW_CFA_undefined: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_undefined DWARF unwind, reg too big"); + return false; + } + results->setRegisterLocation(reg, kRegisterUndefined, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_same_value: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_same_value DWARF unwind, reg too big"); + return false; + } + // DW_CFA_same_value unsupported + // "same value" means register was stored in frame, but its current + // value has not changed, so no need to restore from frame. + // We model this as if the register was never saved. + results->setRegisterLocation(reg, kRegisterUnused, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg); + break; + case DW_CFA_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + reg2 = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg too big"); + return false; + } + if (reg2 > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_register DWARF unwind, reg2 too big"); + return false; + } + results->setRegister(reg, kRegisterInRegister, (int64_t)reg2, + initialState); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2); + break; + case DW_CFA_remember_state: { + // Avoid operator new because that would be an upward dependency. + // Avoid malloc because it needs heap allocation. + PrologInfoStackEntry *entry = + (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC( + sizeof(PrologInfoStackEntry)); + if (entry != NULL) { + entry->next = rememberStack.entry; + entry->info = *results; + rememberStack.entry = entry; + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n"); + break; + } + case DW_CFA_restore_state: + if (rememberStack.entry != NULL) { + PrologInfoStackEntry *top = rememberStack.entry; + *results = top->info; + rememberStack.entry = top->next; + _LIBUNWIND_REMEMBER_FREE(top); + } else { + return false; + } + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n"); + break; + case DW_CFA_def_cfa: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 + ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg); + break; + case DW_CFA_def_cfa_offset: + results->cfaRegisterOffset = + (int32_t)addressSpace.getULEB128(p, instructionsEnd); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_def_cfa_expression: + results->cfaRegister = 0; + results->cfaExpression = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64 + ", length=%" PRIu64 ")\n", + results->cfaExpression, length); + break; + case DW_CFA_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterAtExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", " + "length=%" PRIu64 ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_offset_extended_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big"); + return false; + } + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 ")\n", + reg, offset); + break; + case DW_CFA_def_cfa_offset_sf: + results->cfaRegisterOffset = + (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor); + _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_val_offset: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64 + ") out of range\n", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_offset_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big"); + return false; + } + offset = addressSpace.getSLEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", " + "offset=%" PRId64 "\n", + reg, offset); + break; + case DW_CFA_val_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0( + "malformed DW_CFA_val_expression DWARF unwind, reg too big"); + return false; + } + results->setRegister(reg, kRegisterIsExpression, (int64_t)p, + initialState); + length = addressSpace.getULEB128(p, instructionsEnd); + assert(length < static_cast(~0) && "pointer overflow"); + p += static_cast(length); + _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " + "expression=0x%" PRIx64 ", length=%" PRIu64 + ")\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_GNU_args_size: + length = addressSpace.getULEB128(p, instructionsEnd); + results->spExtraArgSize = (uint32_t)length; + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length); + break; + case DW_CFA_GNU_negative_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF " + "unwind, reg too big"); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, -offset, initialState); + _LIBUNWIND_TRACE_DWARF( + "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset); + break; + +#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) + // The same constant is used to represent different instructions on + // AArch64 (negate_ra_state) and SPARC (window_save). + static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save, + "uses the same constant"); + case DW_CFA_AARCH64_negate_ra_state: + switch (arch) { +#if defined(_LIBUNWIND_TARGET_AARCH64) + case REGISTERS_ARM64: { + int64_t value = + results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1; + results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value, + initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n"); + } break; +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + // case DW_CFA_GNU_window_save: + case REGISTERS_SPARC: + _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n"); + for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) { + results->setRegister(reg, kRegisterInRegister, + ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0, + initialState); + } + + for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) { + results->setRegister(reg, kRegisterInCFA, + ((int64_t)reg - UNW_SPARC_L0) * 4, + initialState); + } + break; +#endif + } + break; +#else + (void)arch; +#endif + + default: + operand = opcode & 0x3F; + switch (opcode & 0xC0) { + case DW_CFA_offset: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) * + cieInfo.dataAlignFactor; + results->setRegister(reg, kRegisterInCFA, offset, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n", + operand, offset); + break; + case DW_CFA_advance_loc: + codeOffset += operand * cieInfo.codeAlignFactor; + _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n", + static_cast(codeOffset)); + break; + case DW_CFA_restore: + reg = operand; + if (reg > kMaxRegisterNumber) { + _LIBUNWIND_LOG( + "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64 + ") out of range", + reg); + return false; + } + results->restoreRegisterToInitialState(reg, initialState); + _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n", + static_cast(operand)); + break; + default: + _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode); + return false; + } + } + } + } + return true; +} + +} // namespace libunwind + +#endif // __DWARF_PARSER_HPP__ diff --git a/libunwind/src/EHHeaderParser.hpp b/libunwind/src/EHHeaderParser.hpp new file mode 100644 index 0000000000..f97cca5482 --- /dev/null +++ b/libunwind/src/EHHeaderParser.hpp @@ -0,0 +1,169 @@ +//===------------------------- EHHeaderParser.hpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Parses ELF .eh_frame_hdr sections. +// +//===----------------------------------------------------------------------===// + +#ifndef __EHHEADERPARSER_HPP__ +#define __EHHEADERPARSER_HPP__ + +#include "libunwind.h" + +#include "DwarfParser.hpp" + +namespace libunwind { + +/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section. +/// +/// See DWARF spec for details: +/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +/// +template class EHHeaderParser { +public: + typedef typename A::pint_t pint_t; + + /// Information encoded in the EH frame header. + struct EHHeaderInfo { + pint_t eh_frame_ptr; + size_t fde_count; + pint_t table; + uint8_t table_enc; + }; + + static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd, + EHHeaderInfo &ehHdrInfo); + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, + uint32_t sectionLength, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo); + +private: + static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry, + pint_t ehHdrStart, pint_t ehHdrEnd, + uint8_t tableEnc, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo); + static size_t getTableEntrySize(uint8_t tableEnc); +}; + +template +bool EHHeaderParser::decodeEHHdr(A &addressSpace, pint_t ehHdrStart, + pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) { + pint_t p = ehHdrStart; + uint8_t version = addressSpace.get8(p++); + if (version != 1) { + _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version"); + return false; + } + + uint8_t eh_frame_ptr_enc = addressSpace.get8(p++); + uint8_t fde_count_enc = addressSpace.get8(p++); + ehHdrInfo.table_enc = addressSpace.get8(p++); + + ehHdrInfo.eh_frame_ptr = + addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart); + ehHdrInfo.fde_count = + fde_count_enc == DW_EH_PE_omit + ? 0 + : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart); + ehHdrInfo.table = p; + + return true; +} + +template +bool EHHeaderParser::decodeTableEntry( + A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd, + uint8_t tableEnc, typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo) { + // Have to decode the whole FDE for the PC range anyway, so just throw away + // the PC start. + addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); + pint_t fde = + addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart); + const char *message = + CFI_Parser::decodeFDE(addressSpace, fde, fdeInfo, cieInfo); + if (message != NULL) { + _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s", + message); + return false; + } + + return true; +} + +template +bool EHHeaderParser::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart, + uint32_t sectionLength, + typename CFI_Parser::FDE_Info *fdeInfo, + typename CFI_Parser::CIE_Info *cieInfo) { + pint_t ehHdrEnd = ehHdrStart + sectionLength; + + EHHeaderParser::EHHeaderInfo hdrInfo; + if (!EHHeaderParser::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, + hdrInfo)) + return false; + + if (hdrInfo.fde_count == 0) return false; + + size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc); + pint_t tableEntry; + + size_t low = 0; + for (size_t len = hdrInfo.fde_count; len > 1;) { + size_t mid = low + (len / 2); + tableEntry = hdrInfo.table + mid * tableEntrySize; + pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd, + hdrInfo.table_enc, ehHdrStart); + + if (start == pc) { + low = mid; + break; + } else if (start < pc) { + low = mid; + len -= (len / 2); + } else { + len /= 2; + } + } + + tableEntry = hdrInfo.table + low * tableEntrySize; + if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd, + hdrInfo.table_enc, fdeInfo, cieInfo)) { + if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd) + return true; + } + + return false; +} + +template +size_t EHHeaderParser::getTableEntrySize(uint8_t tableEnc) { + switch (tableEnc & 0x0f) { + case DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + return 4; + case DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + return 8; + case DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + return 16; + case DW_EH_PE_sleb128: + case DW_EH_PE_uleb128: + _LIBUNWIND_ABORT("Can't binary search on variable length encoded data."); + case DW_EH_PE_omit: + return 0; + default: + _LIBUNWIND_ABORT("Unknown DWARF encoding for search table."); + } +} + +} + +#endif diff --git a/libunwind/src/FrameHeaderCache.hpp b/libunwind/src/FrameHeaderCache.hpp new file mode 100644 index 0000000000..54d5d33c3c --- /dev/null +++ b/libunwind/src/FrameHeaderCache.hpp @@ -0,0 +1,149 @@ +//===-FrameHeaderCache.hpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Cache the elf program headers necessary to unwind the stack more efficiently +// in the presence of many dsos. +// +//===----------------------------------------------------------------------===// + +#ifndef __FRAMEHEADER_CACHE_HPP__ +#define __FRAMEHEADER_CACHE_HPP__ + +#include "config.h" +#include + +#ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__) +#else +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) +#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) +#endif + +// This cache should only be be used from within a dl_iterate_phdr callback. +// dl_iterate_phdr does the necessary synchronization to prevent problems +// with concurrent access via the libc load lock. Adding synchronization +// for other uses is possible, but not currently done. + +class _LIBUNWIND_HIDDEN FrameHeaderCache { + struct CacheEntry { + uintptr_t LowPC() { return Info.dso_base; }; + uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; + UnwindInfoSections Info; + CacheEntry *Next; + }; + + static const size_t kCacheEntryCount = 8; + + // Can't depend on the C++ standard library in libunwind, so use an array to + // allocate the entries, and two linked lists for ordering unused and recently + // used entries. FIXME: Would the the extra memory for a doubly-linked list + // be better than the runtime cost of traversing a very short singly-linked + // list on a cache miss? The entries themselves are all small and consecutive, + // so unlikely to cause page faults when following the pointers. The memory + // spent on additional pointers could also be spent on more entries. + + CacheEntry Entries[kCacheEntryCount]; + CacheEntry *MostRecentlyUsed; + CacheEntry *Unused; + + void resetCache() { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset"); + MostRecentlyUsed = nullptr; + Unused = &Entries[0]; + for (size_t i = 0; i < kCacheEntryCount - 1; i++) { + Entries[i].Next = &Entries[i + 1]; + } + Entries[kCacheEntryCount - 1].Next = nullptr; + } + + bool cacheNeedsReset(dl_phdr_info *PInfo) { + // C libraries increment dl_phdr_info.adds and dl_phdr_info.subs when + // loading and unloading shared libraries. If these values change between + // iterations of dl_iterate_phdr, then invalidate the cache. + + // These are static to avoid needing an initializer, and unsigned long long + // because that is their type within the extended dl_phdr_info. Initialize + // these to something extremely unlikely to be found upon the first call to + // dl_iterate_phdr. + static unsigned long long LastAdds = ULLONG_MAX; + static unsigned long long LastSubs = ULLONG_MAX; + if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) { + // Resetting the entire cache is a big hammer, but this path is rare-- + // usually just on the very first call, when the cache is empty anyway--so + // added complexity doesn't buy much. + LastAdds = PInfo->dlpi_adds; + LastSubs = PInfo->dlpi_subs; + resetCache(); + return true; + } + return false; + } + +public: + bool find(dl_phdr_info *PInfo, size_t, void *data) { + if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr) + return false; + + auto *CBData = static_cast(data); + CacheEntry *Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current != nullptr) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Current->LowPC() <= CBData->targetAddr && + CBData->targetAddr < Current->HighPC()) { + _LIBUNWIND_FRAMEHEADERCACHE_TRACE( + "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr, + Current->LowPC(), Current->HighPC()); + if (Previous) { + // If there is no Previous, then Current is already the + // MostRecentlyUsed, and no need to move it up. + Previous->Next = Current->Next; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + } + *CBData->sects = Current->Info; + return true; + } + Previous = Current; + Current = Current->Next; + } + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx", + CBData->targetAddr); + return false; + } + + void add(const UnwindInfoSections *UIS) { + CacheEntry *Current = nullptr; + + if (Unused != nullptr) { + Current = Unused; + Unused = Unused->Next; + } else { + Current = MostRecentlyUsed; + CacheEntry *Previous = nullptr; + while (Current->Next != nullptr) { + Previous = Current; + Current = Current->Next; + } + Previous->Next = nullptr; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)", + Current->LowPC(), Current->HighPC()); + } + + Current->Info = *UIS; + Current->Next = MostRecentlyUsed; + MostRecentlyUsed = Current; + _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)", + MostRecentlyUsed->LowPC(), + MostRecentlyUsed->HighPC()); + } +}; + +#endif // __FRAMEHEADER_CACHE_HPP__ diff --git a/libunwind/src/RWMutex.hpp b/libunwind/src/RWMutex.hpp new file mode 100644 index 0000000000..fcd3f4967d --- /dev/null +++ b/libunwind/src/RWMutex.hpp @@ -0,0 +1,114 @@ +//===----------------------------- Registers.hpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Abstract interface to shared reader/writer log, hiding platform and +// configuration differences. +// +//===----------------------------------------------------------------------===// + +#ifndef __RWMUTEX_HPP__ +#define __RWMUTEX_HPP__ + +#if defined(_WIN32) +#include +#elif !defined(_LIBUNWIND_HAS_NO_THREADS) +#include +#if defined(__ELF__) && defined(_LIBUNWIND_LINK_PTHREAD_LIB) +#pragma comment(lib, "pthread") +#endif +#endif + +namespace libunwind { + +#if defined(_LIBUNWIND_HAS_NO_THREADS) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return true; } + bool unlock_shared() { return true; } + bool lock() { return true; } + bool unlock() { return true; } +}; + +#elif defined(_WIN32) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + AcquireSRWLockShared(&_lock); + return true; + } + bool unlock_shared() { + ReleaseSRWLockShared(&_lock); + return true; + } + bool lock() { + AcquireSRWLockExclusive(&_lock); + return true; + } + bool unlock() { + ReleaseSRWLockExclusive(&_lock); + return true; + } + +private: + SRWLOCK _lock = SRWLOCK_INIT; +}; + +#elif !defined(LIBUNWIND_USE_WEAK_PTHREAD) + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; } + bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; } + bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; } + bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#else + +extern "C" int __attribute__((weak)) +pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg); +extern "C" int __attribute__((weak)) +pthread_rwlock_rdlock(pthread_rwlock_t *lock); +extern "C" int __attribute__((weak)) +pthread_rwlock_wrlock(pthread_rwlock_t *lock); +extern "C" int __attribute__((weak)) +pthread_rwlock_unlock(pthread_rwlock_t *lock); + +// Calls to the locking functions are gated on pthread_create, and not the +// functions themselves, because the data structure should only be locked if +// another thread has been created. This is what similar libraries do. + +class _LIBUNWIND_HIDDEN RWMutex { +public: + bool lock_shared() { + return !pthread_create || (pthread_rwlock_rdlock(&_lock) == 0); + } + bool unlock_shared() { + return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0); + } + bool lock() { + return !pthread_create || (pthread_rwlock_wrlock(&_lock) == 0); + } + bool unlock() { + return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0); + } + +private: + pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER; +}; + +#endif + +} // namespace libunwind + +#endif // __RWMUTEX_HPP__ diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp new file mode 100644 index 0000000000..5e2f11fbe1 --- /dev/null +++ b/libunwind/src/Registers.hpp @@ -0,0 +1,4509 @@ +//===----------------------------- Registers.hpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Models register sets for supported processors. +// +//===----------------------------------------------------------------------===// + +#ifndef __REGISTERS_HPP__ +#define __REGISTERS_HPP__ + +#include +#include + +#include "cet_unwind.h" +#include "config.h" +#include "libunwind.h" + +namespace libunwind { + +// For emulating 128-bit registers +struct v128 { uint32_t vec[4]; }; + +enum { + REGISTERS_X86, + REGISTERS_X86_64, + REGISTERS_PPC, + REGISTERS_PPC64, + REGISTERS_ARM64, + REGISTERS_ARM, + REGISTERS_OR1K, + REGISTERS_MIPS_O32, + REGISTERS_MIPS_NEWABI, + REGISTERS_SPARC, + REGISTERS_HEXAGON, + REGISTERS_RISCV, + REGISTERS_VE, +}; + +#if defined(_LIBUNWIND_TARGET_I386) +class _LIBUNWIND_HIDDEN Registers_x86; +extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); + +#if defined(_LIBUNWIND_USE_CET) +extern "C" void *__libunwind_cet_get_jump_target() { + return reinterpret_cast(&__libunwind_Registers_x86_jumpto); +} +#endif + +/// Registers_x86 holds the register state of a thread in a 32-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86 { +public: + Registers_x86(); + Registers_x86(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const { return false; } + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_x86_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; } + static int getArch() { return REGISTERS_X86; } + + uint32_t getSP() const { return _registers.__esp; } + void setSP(uint32_t value) { _registers.__esp = value; } + uint32_t getIP() const { return _registers.__eip; } + void setIP(uint32_t value) { _registers.__eip = value; } + uint32_t getEBP() const { return _registers.__ebp; } + void setEBP(uint32_t value) { _registers.__ebp = value; } + uint32_t getEBX() const { return _registers.__ebx; } + void setEBX(uint32_t value) { _registers.__ebx = value; } + uint32_t getECX() const { return _registers.__ecx; } + void setECX(uint32_t value) { _registers.__ecx = value; } + uint32_t getEDX() const { return _registers.__edx; } + void setEDX(uint32_t value) { _registers.__edx = value; } + uint32_t getESI() const { return _registers.__esi; } + void setESI(uint32_t value) { _registers.__esi = value; } + uint32_t getEDI() const { return _registers.__edi; } + void setEDI(uint32_t value) { _registers.__edi = value; } + +private: + struct GPRs { + unsigned int __eax; + unsigned int __ebx; + unsigned int __ecx; + unsigned int __edx; + unsigned int __edi; + unsigned int __esi; + unsigned int __ebp; + unsigned int __esp; + unsigned int __ss; + unsigned int __eflags; + unsigned int __eip; + unsigned int __cs; + unsigned int __ds; + unsigned int __es; + unsigned int __fs; + unsigned int __gs; + }; + + GPRs _registers; +}; + +inline Registers_x86::Registers_x86(const void *registers) { + static_assert((check_fit::does_fit), + "x86 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); +} + +inline Registers_x86::Registers_x86() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_x86::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 7) + return false; + return true; +} + +inline uint32_t Registers_x86::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__eip; + case UNW_REG_SP: + return _registers.__esp; + case UNW_X86_EAX: + return _registers.__eax; + case UNW_X86_ECX: + return _registers.__ecx; + case UNW_X86_EDX: + return _registers.__edx; + case UNW_X86_EBX: + return _registers.__ebx; +#if !defined(__APPLE__) + case UNW_X86_ESP: +#else + case UNW_X86_EBP: +#endif + return _registers.__ebp; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else + case UNW_X86_ESP: +#endif + return _registers.__esp; + case UNW_X86_ESI: + return _registers.__esi; + case UNW_X86_EDI: + return _registers.__edi; + } + _LIBUNWIND_ABORT("unsupported x86 register"); +} + +inline void Registers_x86::setRegister(int regNum, uint32_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__eip = value; + return; + case UNW_REG_SP: + _registers.__esp = value; + return; + case UNW_X86_EAX: + _registers.__eax = value; + return; + case UNW_X86_ECX: + _registers.__ecx = value; + return; + case UNW_X86_EDX: + _registers.__edx = value; + return; + case UNW_X86_EBX: + _registers.__ebx = value; + return; +#if !defined(__APPLE__) + case UNW_X86_ESP: +#else + case UNW_X86_EBP: +#endif + _registers.__ebp = value; + return; +#if !defined(__APPLE__) + case UNW_X86_EBP: +#else + case UNW_X86_ESP: +#endif + _registers.__esp = value; + return; + case UNW_X86_ESI: + _registers.__esi = value; + return; + case UNW_X86_EDI: + _registers.__edi = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86 register"); +} + +inline const char *Registers_x86::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "esp"; + case UNW_X86_EAX: + return "eax"; + case UNW_X86_ECX: + return "ecx"; + case UNW_X86_EDX: + return "edx"; + case UNW_X86_EBX: + return "ebx"; + case UNW_X86_EBP: + return "ebp"; + case UNW_X86_ESP: + return "esp"; + case UNW_X86_ESI: + return "esi"; + case UNW_X86_EDI: + return "edi"; + default: + return "unknown register"; + } +} + +inline double Registers_x86::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86 float registers"); +} + +inline void Registers_x86::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86 float registers"); +} + +inline v128 Registers_x86::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no x86 vector registers"); +} + +inline void Registers_x86::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no x86 vector registers"); +} +#endif // _LIBUNWIND_TARGET_I386 + + +#if defined(_LIBUNWIND_TARGET_X86_64) +/// Registers_x86_64 holds the register state of a thread in a 64-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86_64; +extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); + +#if defined(_LIBUNWIND_USE_CET) +extern "C" void *__libunwind_cet_get_jump_target() { + return reinterpret_cast(&__libunwind_Registers_x86_64_jumpto); +} +#endif + +class _LIBUNWIND_HIDDEN Registers_x86_64 { +public: + Registers_x86_64(); + Registers_x86_64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_x86_64_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; } + static int getArch() { return REGISTERS_X86_64; } + + uint64_t getSP() const { return _registers.__rsp; } + void setSP(uint64_t value) { _registers.__rsp = value; } + uint64_t getIP() const { return _registers.__rip; } + void setIP(uint64_t value) { _registers.__rip = value; } + uint64_t getRBP() const { return _registers.__rbp; } + void setRBP(uint64_t value) { _registers.__rbp = value; } + uint64_t getRBX() const { return _registers.__rbx; } + void setRBX(uint64_t value) { _registers.__rbx = value; } + uint64_t getR12() const { return _registers.__r12; } + void setR12(uint64_t value) { _registers.__r12 = value; } + uint64_t getR13() const { return _registers.__r13; } + void setR13(uint64_t value) { _registers.__r13 = value; } + uint64_t getR14() const { return _registers.__r14; } + void setR14(uint64_t value) { _registers.__r14 = value; } + uint64_t getR15() const { return _registers.__r15; } + void setR15(uint64_t value) { _registers.__r15 = value; } + +private: + struct GPRs { + uint64_t __rax; + uint64_t __rbx; + uint64_t __rcx; + uint64_t __rdx; + uint64_t __rdi; + uint64_t __rsi; + uint64_t __rbp; + uint64_t __rsp; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __rip; + uint64_t __rflags; + uint64_t __cs; + uint64_t __fs; + uint64_t __gs; +#if defined(_WIN64) + uint64_t __padding; // 16-byte align +#endif + }; + GPRs _registers; +#if defined(_WIN64) + v128 _xmm[16]; +#endif +}; + +inline Registers_x86_64::Registers_x86_64(const void *registers) { + static_assert((check_fit::does_fit), + "x86_64 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); +} + +inline Registers_x86_64::Registers_x86_64() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_x86_64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 16) + return false; + return true; +} + +inline uint64_t Registers_x86_64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + case UNW_X86_64_RIP: + return _registers.__rip; + case UNW_REG_SP: + return _registers.__rsp; + case UNW_X86_64_RAX: + return _registers.__rax; + case UNW_X86_64_RDX: + return _registers.__rdx; + case UNW_X86_64_RCX: + return _registers.__rcx; + case UNW_X86_64_RBX: + return _registers.__rbx; + case UNW_X86_64_RSI: + return _registers.__rsi; + case UNW_X86_64_RDI: + return _registers.__rdi; + case UNW_X86_64_RBP: + return _registers.__rbp; + case UNW_X86_64_RSP: + return _registers.__rsp; + case UNW_X86_64_R8: + return _registers.__r8; + case UNW_X86_64_R9: + return _registers.__r9; + case UNW_X86_64_R10: + return _registers.__r10; + case UNW_X86_64_R11: + return _registers.__r11; + case UNW_X86_64_R12: + return _registers.__r12; + case UNW_X86_64_R13: + return _registers.__r13; + case UNW_X86_64_R14: + return _registers.__r14; + case UNW_X86_64_R15: + return _registers.__r15; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + case UNW_X86_64_RIP: + _registers.__rip = value; + return; + case UNW_REG_SP: + _registers.__rsp = value; + return; + case UNW_X86_64_RAX: + _registers.__rax = value; + return; + case UNW_X86_64_RDX: + _registers.__rdx = value; + return; + case UNW_X86_64_RCX: + _registers.__rcx = value; + return; + case UNW_X86_64_RBX: + _registers.__rbx = value; + return; + case UNW_X86_64_RSI: + _registers.__rsi = value; + return; + case UNW_X86_64_RDI: + _registers.__rdi = value; + return; + case UNW_X86_64_RBP: + _registers.__rbp = value; + return; + case UNW_X86_64_RSP: + _registers.__rsp = value; + return; + case UNW_X86_64_R8: + _registers.__r8 = value; + return; + case UNW_X86_64_R9: + _registers.__r9 = value; + return; + case UNW_X86_64_R10: + _registers.__r10 = value; + return; + case UNW_X86_64_R11: + _registers.__r11 = value; + return; + case UNW_X86_64_R12: + _registers.__r12 = value; + return; + case UNW_X86_64_R13: + _registers.__r13 = value; + return; + case UNW_X86_64_R14: + _registers.__r14 = value; + return; + case UNW_X86_64_R15: + _registers.__r15 = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline const char *Registers_x86_64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + case UNW_X86_64_RIP: + return "rip"; + case UNW_REG_SP: + return "rsp"; + case UNW_X86_64_RAX: + return "rax"; + case UNW_X86_64_RDX: + return "rdx"; + case UNW_X86_64_RCX: + return "rcx"; + case UNW_X86_64_RBX: + return "rbx"; + case UNW_X86_64_RSI: + return "rsi"; + case UNW_X86_64_RDI: + return "rdi"; + case UNW_X86_64_RBP: + return "rbp"; + case UNW_X86_64_RSP: + return "rsp"; + case UNW_X86_64_R8: + return "r8"; + case UNW_X86_64_R9: + return "r9"; + case UNW_X86_64_R10: + return "r10"; + case UNW_X86_64_R11: + return "r11"; + case UNW_X86_64_R12: + return "r12"; + case UNW_X86_64_R13: + return "r13"; + case UNW_X86_64_R14: + return "r14"; + case UNW_X86_64_R15: + return "r15"; + case UNW_X86_64_XMM0: + return "xmm0"; + case UNW_X86_64_XMM1: + return "xmm1"; + case UNW_X86_64_XMM2: + return "xmm2"; + case UNW_X86_64_XMM3: + return "xmm3"; + case UNW_X86_64_XMM4: + return "xmm4"; + case UNW_X86_64_XMM5: + return "xmm5"; + case UNW_X86_64_XMM6: + return "xmm6"; + case UNW_X86_64_XMM7: + return "xmm7"; + case UNW_X86_64_XMM8: + return "xmm8"; + case UNW_X86_64_XMM9: + return "xmm9"; + case UNW_X86_64_XMM10: + return "xmm10"; + case UNW_X86_64_XMM11: + return "xmm11"; + case UNW_X86_64_XMM12: + return "xmm12"; + case UNW_X86_64_XMM13: + return "xmm13"; + case UNW_X86_64_XMM14: + return "xmm14"; + case UNW_X86_64_XMM15: + return "xmm15"; + default: + return "unknown register"; + } +} + +inline double Registers_x86_64::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline void Registers_x86_64::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline bool Registers_x86_64::validVectorRegister(int regNum) const { +#if defined(_WIN64) + if (regNum < UNW_X86_64_XMM0) + return false; + if (regNum > UNW_X86_64_XMM15) + return false; + return true; +#else + (void)regNum; // suppress unused parameter warning + return false; +#endif +} + +inline v128 Registers_x86_64::getVectorRegister(int regNum) const { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + return _xmm[regNum - UNW_X86_64_XMM0]; +#else + (void)regNum; // suppress unused parameter warning + _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif +} + +inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) { +#if defined(_WIN64) + assert(validVectorRegister(regNum)); + _xmm[regNum - UNW_X86_64_XMM0] = value; +#else + (void)regNum; (void)value; // suppress unused parameter warnings + _LIBUNWIND_ABORT("no x86_64 vector registers"); +#endif +} +#endif // _LIBUNWIND_TARGET_X86_64 + + +#if defined(_LIBUNWIND_TARGET_PPC) +/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc { +public: + Registers_ppc(); + Registers_ppc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; } + static int getArch() { return REGISTERS_PPC; } + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint32_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint32_t value) { _registers.__srr0 = value; } + +private: + struct ppc_thread_state_t { + unsigned int __srr0; /* Instruction address register (PC) */ + unsigned int __srr1; /* Machine state register (supervisor) */ + unsigned int __r0; + unsigned int __r1; + unsigned int __r2; + unsigned int __r3; + unsigned int __r4; + unsigned int __r5; + unsigned int __r6; + unsigned int __r7; + unsigned int __r8; + unsigned int __r9; + unsigned int __r10; + unsigned int __r11; + unsigned int __r12; + unsigned int __r13; + unsigned int __r14; + unsigned int __r15; + unsigned int __r16; + unsigned int __r17; + unsigned int __r18; + unsigned int __r19; + unsigned int __r20; + unsigned int __r21; + unsigned int __r22; + unsigned int __r23; + unsigned int __r24; + unsigned int __r25; + unsigned int __r26; + unsigned int __r27; + unsigned int __r28; + unsigned int __r29; + unsigned int __r30; + unsigned int __r31; + unsigned int __cr; /* Condition register */ + unsigned int __xer; /* User's integer exception register */ + unsigned int __lr; /* Link register */ + unsigned int __ctr; /* Count register */ + unsigned int __mq; /* MQ register (601 only) */ + unsigned int __vrsave; /* Vector Save Register */ + }; + + struct ppc_float_state_t { + double __fpregs[32]; + + unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ + unsigned int __fpscr; /* floating point status register */ + }; + + ppc_thread_state_t _registers; + ppc_float_state_t _floatRegisters; + v128 _vectorRegisters[32]; // offset 424 +}; + +inline Registers_ppc::Registers_ppc(const void *registers) { + static_assert((check_fit::does_fit), + "ppc registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(ppc_thread_state_t) == 160, + "expected float register offset to be 160"); + memcpy(&_floatRegisters, + static_cast(registers) + sizeof(ppc_thread_state_t), + sizeof(_floatRegisters)); + static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424, + "expected vector register offset to be 424 bytes"); + memcpy(_vectorRegisters, + static_cast(registers) + sizeof(ppc_thread_state_t) + + sizeof(ppc_float_state_t), + sizeof(_vectorRegisters)); +} + +inline Registers_ppc::Registers_ppc() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_floatRegisters, 0, sizeof(_floatRegisters)); + memset(&_vectorRegisters, 0, sizeof(_vectorRegisters)); +} + +inline bool Registers_ppc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum == UNW_PPC_VRSAVE) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_PPC_R31) + return true; + if (regNum == UNW_PPC_MQ) + return true; + if (regNum == UNW_PPC_LR) + return true; + if (regNum == UNW_PPC_CTR) + return true; + if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7)) + return true; + return false; +} + +inline uint32_t Registers_ppc::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC_R0: + return _registers.__r0; + case UNW_PPC_R1: + return _registers.__r1; + case UNW_PPC_R2: + return _registers.__r2; + case UNW_PPC_R3: + return _registers.__r3; + case UNW_PPC_R4: + return _registers.__r4; + case UNW_PPC_R5: + return _registers.__r5; + case UNW_PPC_R6: + return _registers.__r6; + case UNW_PPC_R7: + return _registers.__r7; + case UNW_PPC_R8: + return _registers.__r8; + case UNW_PPC_R9: + return _registers.__r9; + case UNW_PPC_R10: + return _registers.__r10; + case UNW_PPC_R11: + return _registers.__r11; + case UNW_PPC_R12: + return _registers.__r12; + case UNW_PPC_R13: + return _registers.__r13; + case UNW_PPC_R14: + return _registers.__r14; + case UNW_PPC_R15: + return _registers.__r15; + case UNW_PPC_R16: + return _registers.__r16; + case UNW_PPC_R17: + return _registers.__r17; + case UNW_PPC_R18: + return _registers.__r18; + case UNW_PPC_R19: + return _registers.__r19; + case UNW_PPC_R20: + return _registers.__r20; + case UNW_PPC_R21: + return _registers.__r21; + case UNW_PPC_R22: + return _registers.__r22; + case UNW_PPC_R23: + return _registers.__r23; + case UNW_PPC_R24: + return _registers.__r24; + case UNW_PPC_R25: + return _registers.__r25; + case UNW_PPC_R26: + return _registers.__r26; + case UNW_PPC_R27: + return _registers.__r27; + case UNW_PPC_R28: + return _registers.__r28; + case UNW_PPC_R29: + return _registers.__r29; + case UNW_PPC_R30: + return _registers.__r30; + case UNW_PPC_R31: + return _registers.__r31; + case UNW_PPC_LR: + return _registers.__lr; + case UNW_PPC_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline void Registers_ppc::setRegister(int regNum, uint32_t value) { + //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC_R0: + _registers.__r0 = value; + return; + case UNW_PPC_R1: + _registers.__r1 = value; + return; + case UNW_PPC_R2: + _registers.__r2 = value; + return; + case UNW_PPC_R3: + _registers.__r3 = value; + return; + case UNW_PPC_R4: + _registers.__r4 = value; + return; + case UNW_PPC_R5: + _registers.__r5 = value; + return; + case UNW_PPC_R6: + _registers.__r6 = value; + return; + case UNW_PPC_R7: + _registers.__r7 = value; + return; + case UNW_PPC_R8: + _registers.__r8 = value; + return; + case UNW_PPC_R9: + _registers.__r9 = value; + return; + case UNW_PPC_R10: + _registers.__r10 = value; + return; + case UNW_PPC_R11: + _registers.__r11 = value; + return; + case UNW_PPC_R12: + _registers.__r12 = value; + return; + case UNW_PPC_R13: + _registers.__r13 = value; + return; + case UNW_PPC_R14: + _registers.__r14 = value; + return; + case UNW_PPC_R15: + _registers.__r15 = value; + return; + case UNW_PPC_R16: + _registers.__r16 = value; + return; + case UNW_PPC_R17: + _registers.__r17 = value; + return; + case UNW_PPC_R18: + _registers.__r18 = value; + return; + case UNW_PPC_R19: + _registers.__r19 = value; + return; + case UNW_PPC_R20: + _registers.__r20 = value; + return; + case UNW_PPC_R21: + _registers.__r21 = value; + return; + case UNW_PPC_R22: + _registers.__r22 = value; + return; + case UNW_PPC_R23: + _registers.__r23 = value; + return; + case UNW_PPC_R24: + _registers.__r24 = value; + return; + case UNW_PPC_R25: + _registers.__r25 = value; + return; + case UNW_PPC_R26: + _registers.__r26 = value; + return; + case UNW_PPC_R27: + _registers.__r27 = value; + return; + case UNW_PPC_R28: + _registers.__r28 = value; + return; + case UNW_PPC_R29: + _registers.__r29 = value; + return; + case UNW_PPC_R30: + _registers.__r30 = value; + return; + case UNW_PPC_R31: + _registers.__r31 = value; + return; + case UNW_PPC_MQ: + _registers.__mq = value; + return; + case UNW_PPC_LR: + _registers.__lr = value; + return; + case UNW_PPC_CTR: + _registers.__ctr = value; + return; + case UNW_PPC_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC_VRSAVE: + _registers.__vrsave = value; + return; + // not saved + return; + case UNW_PPC_XER: + _registers.__xer = value; + return; + case UNW_PPC_AP: + case UNW_PPC_VSCR: + case UNW_PPC_SPEFSCR: + // not saved + return; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline bool Registers_ppc::validFloatRegister(int regNum) const { + if (regNum < UNW_PPC_F0) + return false; + if (regNum > UNW_PPC_F31) + return false; + return true; +} + +inline double Registers_ppc::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; +} + +inline void Registers_ppc::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; +} + +inline bool Registers_ppc::validVectorRegister(int regNum) const { + if (regNum < UNW_PPC_V0) + return false; + if (regNum > UNW_PPC_V31) + return false; + return true; +} + +inline v128 Registers_ppc::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; + return result; +} + +inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorRegisters[regNum - UNW_PPC_V0] = value; +} + +inline const char *Registers_ppc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC_R0: + return "r0"; + case UNW_PPC_R1: + return "r1"; + case UNW_PPC_R2: + return "r2"; + case UNW_PPC_R3: + return "r3"; + case UNW_PPC_R4: + return "r4"; + case UNW_PPC_R5: + return "r5"; + case UNW_PPC_R6: + return "r6"; + case UNW_PPC_R7: + return "r7"; + case UNW_PPC_R8: + return "r8"; + case UNW_PPC_R9: + return "r9"; + case UNW_PPC_R10: + return "r10"; + case UNW_PPC_R11: + return "r11"; + case UNW_PPC_R12: + return "r12"; + case UNW_PPC_R13: + return "r13"; + case UNW_PPC_R14: + return "r14"; + case UNW_PPC_R15: + return "r15"; + case UNW_PPC_R16: + return "r16"; + case UNW_PPC_R17: + return "r17"; + case UNW_PPC_R18: + return "r18"; + case UNW_PPC_R19: + return "r19"; + case UNW_PPC_R20: + return "r20"; + case UNW_PPC_R21: + return "r21"; + case UNW_PPC_R22: + return "r22"; + case UNW_PPC_R23: + return "r23"; + case UNW_PPC_R24: + return "r24"; + case UNW_PPC_R25: + return "r25"; + case UNW_PPC_R26: + return "r26"; + case UNW_PPC_R27: + return "r27"; + case UNW_PPC_R28: + return "r28"; + case UNW_PPC_R29: + return "r29"; + case UNW_PPC_R30: + return "r30"; + case UNW_PPC_R31: + return "r31"; + case UNW_PPC_F0: + return "fp0"; + case UNW_PPC_F1: + return "fp1"; + case UNW_PPC_F2: + return "fp2"; + case UNW_PPC_F3: + return "fp3"; + case UNW_PPC_F4: + return "fp4"; + case UNW_PPC_F5: + return "fp5"; + case UNW_PPC_F6: + return "fp6"; + case UNW_PPC_F7: + return "fp7"; + case UNW_PPC_F8: + return "fp8"; + case UNW_PPC_F9: + return "fp9"; + case UNW_PPC_F10: + return "fp10"; + case UNW_PPC_F11: + return "fp11"; + case UNW_PPC_F12: + return "fp12"; + case UNW_PPC_F13: + return "fp13"; + case UNW_PPC_F14: + return "fp14"; + case UNW_PPC_F15: + return "fp15"; + case UNW_PPC_F16: + return "fp16"; + case UNW_PPC_F17: + return "fp17"; + case UNW_PPC_F18: + return "fp18"; + case UNW_PPC_F19: + return "fp19"; + case UNW_PPC_F20: + return "fp20"; + case UNW_PPC_F21: + return "fp21"; + case UNW_PPC_F22: + return "fp22"; + case UNW_PPC_F23: + return "fp23"; + case UNW_PPC_F24: + return "fp24"; + case UNW_PPC_F25: + return "fp25"; + case UNW_PPC_F26: + return "fp26"; + case UNW_PPC_F27: + return "fp27"; + case UNW_PPC_F28: + return "fp28"; + case UNW_PPC_F29: + return "fp29"; + case UNW_PPC_F30: + return "fp30"; + case UNW_PPC_F31: + return "fp31"; + case UNW_PPC_LR: + return "lr"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_PPC + +#if defined(_LIBUNWIND_TARGET_PPC64) +/// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc64 { +public: + Registers_ppc64(); + Registers_ppc64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; } + static int getArch() { return REGISTERS_PPC64; } + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint64_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint64_t value) { _registers.__srr0 = value; } + +private: + struct ppc64_thread_state_t { + uint64_t __srr0; // Instruction address register (PC) + uint64_t __srr1; // Machine state register (supervisor) + uint64_t __r0; + uint64_t __r1; + uint64_t __r2; + uint64_t __r3; + uint64_t __r4; + uint64_t __r5; + uint64_t __r6; + uint64_t __r7; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __r16; + uint64_t __r17; + uint64_t __r18; + uint64_t __r19; + uint64_t __r20; + uint64_t __r21; + uint64_t __r22; + uint64_t __r23; + uint64_t __r24; + uint64_t __r25; + uint64_t __r26; + uint64_t __r27; + uint64_t __r28; + uint64_t __r29; + uint64_t __r30; + uint64_t __r31; + uint64_t __cr; // Condition register + uint64_t __xer; // User's integer exception register + uint64_t __lr; // Link register + uint64_t __ctr; // Count register + uint64_t __vrsave; // Vector Save Register + }; + + union ppc64_vsr_t { + struct asfloat_s { + double f; + uint64_t v2; + } asfloat; + v128 v; + }; + + ppc64_thread_state_t _registers; + ppc64_vsr_t _vectorScalarRegisters[64]; + + static int getVectorRegNum(int num); +}; + +inline Registers_ppc64::Registers_ppc64(const void *registers) { + static_assert((check_fit::does_fit), + "ppc64 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(_registers) == 312, + "expected vector scalar register offset to be 312"); + memcpy(&_vectorScalarRegisters, + static_cast(registers) + sizeof(_registers), + sizeof(_vectorScalarRegisters)); + static_assert(sizeof(_registers) + + sizeof(_vectorScalarRegisters) == 1336, + "expected vector register offset to be 1336 bytes"); +} + +inline Registers_ppc64::Registers_ppc64() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters)); +} + +inline bool Registers_ppc64::validRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + case UNW_REG_SP: + case UNW_PPC64_XER: + case UNW_PPC64_LR: + case UNW_PPC64_CTR: + case UNW_PPC64_VRSAVE: + return true; + } + + if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31) + return true; + if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7) + return true; + + return false; +} + +inline uint64_t Registers_ppc64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_PPC64_R0: + return _registers.__r0; + case UNW_PPC64_R1: + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC64_R2: + return _registers.__r2; + case UNW_PPC64_R3: + return _registers.__r3; + case UNW_PPC64_R4: + return _registers.__r4; + case UNW_PPC64_R5: + return _registers.__r5; + case UNW_PPC64_R6: + return _registers.__r6; + case UNW_PPC64_R7: + return _registers.__r7; + case UNW_PPC64_R8: + return _registers.__r8; + case UNW_PPC64_R9: + return _registers.__r9; + case UNW_PPC64_R10: + return _registers.__r10; + case UNW_PPC64_R11: + return _registers.__r11; + case UNW_PPC64_R12: + return _registers.__r12; + case UNW_PPC64_R13: + return _registers.__r13; + case UNW_PPC64_R14: + return _registers.__r14; + case UNW_PPC64_R15: + return _registers.__r15; + case UNW_PPC64_R16: + return _registers.__r16; + case UNW_PPC64_R17: + return _registers.__r17; + case UNW_PPC64_R18: + return _registers.__r18; + case UNW_PPC64_R19: + return _registers.__r19; + case UNW_PPC64_R20: + return _registers.__r20; + case UNW_PPC64_R21: + return _registers.__r21; + case UNW_PPC64_R22: + return _registers.__r22; + case UNW_PPC64_R23: + return _registers.__r23; + case UNW_PPC64_R24: + return _registers.__r24; + case UNW_PPC64_R25: + return _registers.__r25; + case UNW_PPC64_R26: + return _registers.__r26; + case UNW_PPC64_R27: + return _registers.__r27; + case UNW_PPC64_R28: + return _registers.__r28; + case UNW_PPC64_R29: + return _registers.__r29; + case UNW_PPC64_R30: + return _registers.__r30; + case UNW_PPC64_R31: + return _registers.__r31; + case UNW_PPC64_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC64_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC64_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC64_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC64_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC64_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC64_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC64_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC64_XER: + return _registers.__xer; + case UNW_PPC64_LR: + return _registers.__lr; + case UNW_PPC64_CTR: + return _registers.__ctr; + case UNW_PPC64_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline void Registers_ppc64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_PPC64_R0: + _registers.__r0 = value; + return; + case UNW_PPC64_R1: + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC64_R2: + _registers.__r2 = value; + return; + case UNW_PPC64_R3: + _registers.__r3 = value; + return; + case UNW_PPC64_R4: + _registers.__r4 = value; + return; + case UNW_PPC64_R5: + _registers.__r5 = value; + return; + case UNW_PPC64_R6: + _registers.__r6 = value; + return; + case UNW_PPC64_R7: + _registers.__r7 = value; + return; + case UNW_PPC64_R8: + _registers.__r8 = value; + return; + case UNW_PPC64_R9: + _registers.__r9 = value; + return; + case UNW_PPC64_R10: + _registers.__r10 = value; + return; + case UNW_PPC64_R11: + _registers.__r11 = value; + return; + case UNW_PPC64_R12: + _registers.__r12 = value; + return; + case UNW_PPC64_R13: + _registers.__r13 = value; + return; + case UNW_PPC64_R14: + _registers.__r14 = value; + return; + case UNW_PPC64_R15: + _registers.__r15 = value; + return; + case UNW_PPC64_R16: + _registers.__r16 = value; + return; + case UNW_PPC64_R17: + _registers.__r17 = value; + return; + case UNW_PPC64_R18: + _registers.__r18 = value; + return; + case UNW_PPC64_R19: + _registers.__r19 = value; + return; + case UNW_PPC64_R20: + _registers.__r20 = value; + return; + case UNW_PPC64_R21: + _registers.__r21 = value; + return; + case UNW_PPC64_R22: + _registers.__r22 = value; + return; + case UNW_PPC64_R23: + _registers.__r23 = value; + return; + case UNW_PPC64_R24: + _registers.__r24 = value; + return; + case UNW_PPC64_R25: + _registers.__r25 = value; + return; + case UNW_PPC64_R26: + _registers.__r26 = value; + return; + case UNW_PPC64_R27: + _registers.__r27 = value; + return; + case UNW_PPC64_R28: + _registers.__r28 = value; + return; + case UNW_PPC64_R29: + _registers.__r29 = value; + return; + case UNW_PPC64_R30: + _registers.__r30 = value; + return; + case UNW_PPC64_R31: + _registers.__r31 = value; + return; + case UNW_PPC64_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC64_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC64_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC64_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC64_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC64_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC64_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC64_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC64_XER: + _registers.__xer = value; + return; + case UNW_PPC64_LR: + _registers.__lr = value; + return; + case UNW_PPC64_CTR: + _registers.__ctr = value; + return; + case UNW_PPC64_VRSAVE: + _registers.__vrsave = value; + return; + } + _LIBUNWIND_ABORT("unsupported ppc64 register"); +} + +inline bool Registers_ppc64::validFloatRegister(int regNum) const { + return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31; +} + +inline double Registers_ppc64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f; +} + +inline void Registers_ppc64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value; +} + +inline bool Registers_ppc64::validVectorRegister(int regNum) const { +#if defined(__VSX__) + if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31) + return true; + if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63) + return true; +#elif defined(__ALTIVEC__) + if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31) + return true; +#endif + return false; +} + +inline int Registers_ppc64::getVectorRegNum(int num) +{ + if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31) + return num - UNW_PPC64_VS0; + else + return num - UNW_PPC64_VS32 + 32; +} + +inline v128 Registers_ppc64::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + return _vectorScalarRegisters[getVectorRegNum(regNum)].v; +} + +inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorScalarRegisters[getVectorRegNum(regNum)].v = value; +} + +inline const char *Registers_ppc64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC64_R0: + return "r0"; + case UNW_PPC64_R1: + return "r1"; + case UNW_PPC64_R2: + return "r2"; + case UNW_PPC64_R3: + return "r3"; + case UNW_PPC64_R4: + return "r4"; + case UNW_PPC64_R5: + return "r5"; + case UNW_PPC64_R6: + return "r6"; + case UNW_PPC64_R7: + return "r7"; + case UNW_PPC64_R8: + return "r8"; + case UNW_PPC64_R9: + return "r9"; + case UNW_PPC64_R10: + return "r10"; + case UNW_PPC64_R11: + return "r11"; + case UNW_PPC64_R12: + return "r12"; + case UNW_PPC64_R13: + return "r13"; + case UNW_PPC64_R14: + return "r14"; + case UNW_PPC64_R15: + return "r15"; + case UNW_PPC64_R16: + return "r16"; + case UNW_PPC64_R17: + return "r17"; + case UNW_PPC64_R18: + return "r18"; + case UNW_PPC64_R19: + return "r19"; + case UNW_PPC64_R20: + return "r20"; + case UNW_PPC64_R21: + return "r21"; + case UNW_PPC64_R22: + return "r22"; + case UNW_PPC64_R23: + return "r23"; + case UNW_PPC64_R24: + return "r24"; + case UNW_PPC64_R25: + return "r25"; + case UNW_PPC64_R26: + return "r26"; + case UNW_PPC64_R27: + return "r27"; + case UNW_PPC64_R28: + return "r28"; + case UNW_PPC64_R29: + return "r29"; + case UNW_PPC64_R30: + return "r30"; + case UNW_PPC64_R31: + return "r31"; + case UNW_PPC64_CR0: + return "cr0"; + case UNW_PPC64_CR1: + return "cr1"; + case UNW_PPC64_CR2: + return "cr2"; + case UNW_PPC64_CR3: + return "cr3"; + case UNW_PPC64_CR4: + return "cr4"; + case UNW_PPC64_CR5: + return "cr5"; + case UNW_PPC64_CR6: + return "cr6"; + case UNW_PPC64_CR7: + return "cr7"; + case UNW_PPC64_XER: + return "xer"; + case UNW_PPC64_LR: + return "lr"; + case UNW_PPC64_CTR: + return "ctr"; + case UNW_PPC64_VRSAVE: + return "vrsave"; + case UNW_PPC64_F0: + return "fp0"; + case UNW_PPC64_F1: + return "fp1"; + case UNW_PPC64_F2: + return "fp2"; + case UNW_PPC64_F3: + return "fp3"; + case UNW_PPC64_F4: + return "fp4"; + case UNW_PPC64_F5: + return "fp5"; + case UNW_PPC64_F6: + return "fp6"; + case UNW_PPC64_F7: + return "fp7"; + case UNW_PPC64_F8: + return "fp8"; + case UNW_PPC64_F9: + return "fp9"; + case UNW_PPC64_F10: + return "fp10"; + case UNW_PPC64_F11: + return "fp11"; + case UNW_PPC64_F12: + return "fp12"; + case UNW_PPC64_F13: + return "fp13"; + case UNW_PPC64_F14: + return "fp14"; + case UNW_PPC64_F15: + return "fp15"; + case UNW_PPC64_F16: + return "fp16"; + case UNW_PPC64_F17: + return "fp17"; + case UNW_PPC64_F18: + return "fp18"; + case UNW_PPC64_F19: + return "fp19"; + case UNW_PPC64_F20: + return "fp20"; + case UNW_PPC64_F21: + return "fp21"; + case UNW_PPC64_F22: + return "fp22"; + case UNW_PPC64_F23: + return "fp23"; + case UNW_PPC64_F24: + return "fp24"; + case UNW_PPC64_F25: + return "fp25"; + case UNW_PPC64_F26: + return "fp26"; + case UNW_PPC64_F27: + return "fp27"; + case UNW_PPC64_F28: + return "fp28"; + case UNW_PPC64_F29: + return "fp29"; + case UNW_PPC64_F30: + return "fp30"; + case UNW_PPC64_F31: + return "fp31"; + case UNW_PPC64_V0: + return "v0"; + case UNW_PPC64_V1: + return "v1"; + case UNW_PPC64_V2: + return "v2"; + case UNW_PPC64_V3: + return "v3"; + case UNW_PPC64_V4: + return "v4"; + case UNW_PPC64_V5: + return "v5"; + case UNW_PPC64_V6: + return "v6"; + case UNW_PPC64_V7: + return "v7"; + case UNW_PPC64_V8: + return "v8"; + case UNW_PPC64_V9: + return "v9"; + case UNW_PPC64_V10: + return "v10"; + case UNW_PPC64_V11: + return "v11"; + case UNW_PPC64_V12: + return "v12"; + case UNW_PPC64_V13: + return "v13"; + case UNW_PPC64_V14: + return "v14"; + case UNW_PPC64_V15: + return "v15"; + case UNW_PPC64_V16: + return "v16"; + case UNW_PPC64_V17: + return "v17"; + case UNW_PPC64_V18: + return "v18"; + case UNW_PPC64_V19: + return "v19"; + case UNW_PPC64_V20: + return "v20"; + case UNW_PPC64_V21: + return "v21"; + case UNW_PPC64_V22: + return "v22"; + case UNW_PPC64_V23: + return "v23"; + case UNW_PPC64_V24: + return "v24"; + case UNW_PPC64_V25: + return "v25"; + case UNW_PPC64_V26: + return "v26"; + case UNW_PPC64_V27: + return "v27"; + case UNW_PPC64_V28: + return "v28"; + case UNW_PPC64_V29: + return "v29"; + case UNW_PPC64_V30: + return "v30"; + case UNW_PPC64_V31: + return "v31"; + } + return "unknown register"; +} +#endif // _LIBUNWIND_TARGET_PPC64 + + +#if defined(_LIBUNWIND_TARGET_AARCH64) +/// Registers_arm64 holds the register state of a thread in a 64-bit arm +/// process. +class _LIBUNWIND_HIDDEN Registers_arm64; +extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +class _LIBUNWIND_HIDDEN Registers_arm64 { +public: + Registers_arm64(); + Registers_arm64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { __libunwind_Registers_arm64_jumpto(this); } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; } + static int getArch() { return REGISTERS_ARM64; } + + uint64_t getSP() const { return _registers.__sp; } + void setSP(uint64_t value) { _registers.__sp = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + uint64_t getFP() const { return _registers.__fp; } + void setFP(uint64_t value) { _registers.__fp = value; } + +private: + struct GPRs { + uint64_t __x[29]; // x0-x28 + uint64_t __fp; // Frame pointer x29 + uint64_t __lr; // Link register x30 + uint64_t __sp; // Stack pointer x31 + uint64_t __pc; // Program counter + uint64_t __ra_sign_state; // RA sign state register + }; + + GPRs _registers; + double _vectorHalfRegisters[32]; + // Currently only the lower double in 128-bit vectore registers + // is perserved during unwinding. We could define new register + // numbers (> 96) which mean whole vector registers, then this + // struct would need to change to contain whole vector registers. +}; + +inline Registers_arm64::Registers_arm64(const void *registers) { + static_assert((check_fit::does_fit), + "arm64 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + static_assert(sizeof(GPRs) == 0x110, + "expected VFP registers to be at offset 272"); + memcpy(_vectorHalfRegisters, + static_cast(registers) + sizeof(GPRs), + sizeof(_vectorHalfRegisters)); +} + +inline Registers_arm64::Registers_arm64() { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters)); +} + +inline bool Registers_arm64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 95) + return false; + if (regNum == UNW_AARCH64_RA_SIGN_STATE) + return true; + if ((regNum > 32) && (regNum < 64)) + return false; + return true; +} + +inline uint64_t Registers_arm64::getRegister(int regNum) const { + if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC) + return _registers.__pc; + if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP) + return _registers.__sp; + if (regNum == UNW_AARCH64_RA_SIGN_STATE) + return _registers.__ra_sign_state; + if (regNum == UNW_AARCH64_FP) + return _registers.__fp; + if (regNum == UNW_AARCH64_LR) + return _registers.__lr; + if ((regNum >= 0) && (regNum < 29)) + return _registers.__x[regNum]; + _LIBUNWIND_ABORT("unsupported arm64 register"); +} + +inline void Registers_arm64::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC) + _registers.__pc = value; + else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP) + _registers.__sp = value; + else if (regNum == UNW_AARCH64_RA_SIGN_STATE) + _registers.__ra_sign_state = value; + else if (regNum == UNW_AARCH64_FP) + _registers.__fp = value; + else if (regNum == UNW_AARCH64_LR) + _registers.__lr = value; + else if ((regNum >= 0) && (regNum < 29)) + _registers.__x[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported arm64 register"); +} + +inline const char *Registers_arm64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_AARCH64_X0: + return "x0"; + case UNW_AARCH64_X1: + return "x1"; + case UNW_AARCH64_X2: + return "x2"; + case UNW_AARCH64_X3: + return "x3"; + case UNW_AARCH64_X4: + return "x4"; + case UNW_AARCH64_X5: + return "x5"; + case UNW_AARCH64_X6: + return "x6"; + case UNW_AARCH64_X7: + return "x7"; + case UNW_AARCH64_X8: + return "x8"; + case UNW_AARCH64_X9: + return "x9"; + case UNW_AARCH64_X10: + return "x10"; + case UNW_AARCH64_X11: + return "x11"; + case UNW_AARCH64_X12: + return "x12"; + case UNW_AARCH64_X13: + return "x13"; + case UNW_AARCH64_X14: + return "x14"; + case UNW_AARCH64_X15: + return "x15"; + case UNW_AARCH64_X16: + return "x16"; + case UNW_AARCH64_X17: + return "x17"; + case UNW_AARCH64_X18: + return "x18"; + case UNW_AARCH64_X19: + return "x19"; + case UNW_AARCH64_X20: + return "x20"; + case UNW_AARCH64_X21: + return "x21"; + case UNW_AARCH64_X22: + return "x22"; + case UNW_AARCH64_X23: + return "x23"; + case UNW_AARCH64_X24: + return "x24"; + case UNW_AARCH64_X25: + return "x25"; + case UNW_AARCH64_X26: + return "x26"; + case UNW_AARCH64_X27: + return "x27"; + case UNW_AARCH64_X28: + return "x28"; + case UNW_AARCH64_FP: + return "fp"; + case UNW_AARCH64_LR: + return "lr"; + case UNW_AARCH64_SP: + return "sp"; + case UNW_AARCH64_PC: + return "pc"; + case UNW_AARCH64_V0: + return "d0"; + case UNW_AARCH64_V1: + return "d1"; + case UNW_AARCH64_V2: + return "d2"; + case UNW_AARCH64_V3: + return "d3"; + case UNW_AARCH64_V4: + return "d4"; + case UNW_AARCH64_V5: + return "d5"; + case UNW_AARCH64_V6: + return "d6"; + case UNW_AARCH64_V7: + return "d7"; + case UNW_AARCH64_V8: + return "d8"; + case UNW_AARCH64_V9: + return "d9"; + case UNW_AARCH64_V10: + return "d10"; + case UNW_AARCH64_V11: + return "d11"; + case UNW_AARCH64_V12: + return "d12"; + case UNW_AARCH64_V13: + return "d13"; + case UNW_AARCH64_V14: + return "d14"; + case UNW_AARCH64_V15: + return "d15"; + case UNW_AARCH64_V16: + return "d16"; + case UNW_AARCH64_V17: + return "d17"; + case UNW_AARCH64_V18: + return "d18"; + case UNW_AARCH64_V19: + return "d19"; + case UNW_AARCH64_V20: + return "d20"; + case UNW_AARCH64_V21: + return "d21"; + case UNW_AARCH64_V22: + return "d22"; + case UNW_AARCH64_V23: + return "d23"; + case UNW_AARCH64_V24: + return "d24"; + case UNW_AARCH64_V25: + return "d25"; + case UNW_AARCH64_V26: + return "d26"; + case UNW_AARCH64_V27: + return "d27"; + case UNW_AARCH64_V28: + return "d28"; + case UNW_AARCH64_V29: + return "d29"; + case UNW_AARCH64_V30: + return "d30"; + case UNW_AARCH64_V31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_arm64::validFloatRegister(int regNum) const { + if (regNum < UNW_AARCH64_V0) + return false; + if (regNum > UNW_AARCH64_V31) + return false; + return true; +} + +inline double Registers_arm64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorHalfRegisters[regNum - UNW_AARCH64_V0]; +} + +inline void Registers_arm64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorHalfRegisters[regNum - UNW_AARCH64_V0] = value; +} + +inline bool Registers_arm64::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm64::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} + +inline void Registers_arm64::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_AARCH64 + +#if defined(_LIBUNWIND_TARGET_ARM) +/// Registers_arm holds the register state of a thread in a 32-bit arm +/// process. +/// +/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit, +/// this uses more memory than required. +class _LIBUNWIND_HIDDEN Registers_arm { +public: + Registers_arm(); + Registers_arm(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + unw_fpreg_t getFloatRegister(int num); + void setFloatRegister(int num, unw_fpreg_t value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto() { + restoreSavedFloatRegisters(); + restoreCoreAndJumpTo(); + } + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; } + static int getArch() { return REGISTERS_ARM; } + + uint32_t getSP() const { return _registers.__sp; } + void setSP(uint32_t value) { _registers.__sp = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + + void saveVFPAsX() { + assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); + _use_X_for_vfp_save = true; + } + + void restoreSavedFloatRegisters() { + if (_saved_vfp_d0_d15) { + if (_use_X_for_vfp_save) + restoreVFPWithFLDMX(_vfp_d0_d15_pad); + else + restoreVFPWithFLDMD(_vfp_d0_d15_pad); + } + if (_saved_vfp_d16_d31) + restoreVFPv3(_vfp_d16_d31); +#if defined(__ARM_WMMX) + if (_saved_iwmmx) + restoreiWMMX(_iwmmx); + if (_saved_iwmmx_control) + restoreiWMMXControl(_iwmmx_control); +#endif + } + +private: + struct GPRs { + uint32_t __r[13]; // r0-r12 + uint32_t __sp; // Stack pointer r13 + uint32_t __lr; // Link register r14 + uint32_t __pc; // Program counter r15 + }; + + static void saveVFPWithFSTMD(void*); + static void saveVFPWithFSTMX(void*); + static void saveVFPv3(void*); + static void restoreVFPWithFLDMD(void*); + static void restoreVFPWithFLDMX(void*); + static void restoreVFPv3(void*); +#if defined(__ARM_WMMX) + static void saveiWMMX(void*); + static void saveiWMMXControl(uint32_t*); + static void restoreiWMMX(void*); + static void restoreiWMMXControl(uint32_t*); +#endif + void restoreCoreAndJumpTo(); + + // ARM registers + GPRs _registers; + + // We save floating point registers lazily because we can't know ahead of + // time which ones are used. See EHABI #4.7. + + // Whether D0-D15 are saved in the FTSMX instead of FSTMD format. + // + // See EHABI #7.5 that explains how matching instruction sequences for load + // and store need to be used to correctly restore the exact register bits. + bool _use_X_for_vfp_save; + // Whether VFP D0-D15 are saved. + bool _saved_vfp_d0_d15; + // Whether VFPv3 D16-D31 are saved. + bool _saved_vfp_d16_d31; + // VFP registers D0-D15, + padding if saved using FSTMX + unw_fpreg_t _vfp_d0_d15_pad[17]; + // VFPv3 registers D16-D31, always saved using FSTMD + unw_fpreg_t _vfp_d16_d31[16]; +#if defined(__ARM_WMMX) + // Whether iWMMX data registers are saved. + bool _saved_iwmmx; + // Whether iWMMX control registers are saved. + mutable bool _saved_iwmmx_control; + // iWMMX registers + unw_fpreg_t _iwmmx[16]; + // iWMMX control registers + mutable uint32_t _iwmmx_control[4]; +#endif +}; + +inline Registers_arm::Registers_arm(const void *registers) + : _use_X_for_vfp_save(false), + _saved_vfp_d0_d15(false), + _saved_vfp_d16_d31(false) { + static_assert((check_fit::does_fit), + "arm registers do not fit into unw_context_t"); + // See __unw_getcontext() note about data. + memcpy(&_registers, registers, sizeof(_registers)); + memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); + memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; + memset(&_iwmmx, 0, sizeof(_iwmmx)); + memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif +} + +inline Registers_arm::Registers_arm() + : _use_X_for_vfp_save(false), + _saved_vfp_d0_d15(false), + _saved_vfp_d16_d31(false) { + memset(&_registers, 0, sizeof(_registers)); + memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); + memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); +#if defined(__ARM_WMMX) + _saved_iwmmx = false; + _saved_iwmmx_control = false; + memset(&_iwmmx, 0, sizeof(_iwmmx)); + memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); +#endif +} + +inline bool Registers_arm::validRegister(int regNum) const { + // Returns true for all non-VFP registers supported by the EHABI + // virtual register set (VRS). + if (regNum == UNW_REG_IP) + return true; + + if (regNum == UNW_REG_SP) + return true; + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) + return true; + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) + return true; +#endif + + return false; +} + +inline uint32_t Registers_arm::getRegister(int regNum) const { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + return _registers.__sp; + + if (regNum == UNW_ARM_LR) + return _registers.__lr; + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + return _registers.__pc; + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) + return _registers.__r[regNum]; + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { + if (!_saved_iwmmx_control) { + _saved_iwmmx_control = true; + saveiWMMXControl(_iwmmx_control); + } + return _iwmmx_control[regNum - UNW_ARM_WC0]; + } +#endif + + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline void Registers_arm::setRegister(int regNum, uint32_t value) { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { + _registers.__sp = value; + return; + } + + if (regNum == UNW_ARM_LR) { + _registers.__lr = value; + return; + } + + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) { + _registers.__pc = value; + return; + } + + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) { + _registers.__r[regNum] = value; + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { + if (!_saved_iwmmx_control) { + _saved_iwmmx_control = true; + saveiWMMXControl(_iwmmx_control); + } + _iwmmx_control[regNum - UNW_ARM_WC0] = value; + return; + } +#endif + + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline const char *Registers_arm::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + case UNW_ARM_IP: // UNW_ARM_R15 is alias + return "pc"; + case UNW_ARM_LR: // UNW_ARM_R14 is alias + return "lr"; + case UNW_REG_SP: + case UNW_ARM_SP: // UNW_ARM_R13 is alias + return "sp"; + case UNW_ARM_R0: + return "r0"; + case UNW_ARM_R1: + return "r1"; + case UNW_ARM_R2: + return "r2"; + case UNW_ARM_R3: + return "r3"; + case UNW_ARM_R4: + return "r4"; + case UNW_ARM_R5: + return "r5"; + case UNW_ARM_R6: + return "r6"; + case UNW_ARM_R7: + return "r7"; + case UNW_ARM_R8: + return "r8"; + case UNW_ARM_R9: + return "r9"; + case UNW_ARM_R10: + return "r10"; + case UNW_ARM_R11: + return "r11"; + case UNW_ARM_R12: + return "r12"; + case UNW_ARM_S0: + return "s0"; + case UNW_ARM_S1: + return "s1"; + case UNW_ARM_S2: + return "s2"; + case UNW_ARM_S3: + return "s3"; + case UNW_ARM_S4: + return "s4"; + case UNW_ARM_S5: + return "s5"; + case UNW_ARM_S6: + return "s6"; + case UNW_ARM_S7: + return "s7"; + case UNW_ARM_S8: + return "s8"; + case UNW_ARM_S9: + return "s9"; + case UNW_ARM_S10: + return "s10"; + case UNW_ARM_S11: + return "s11"; + case UNW_ARM_S12: + return "s12"; + case UNW_ARM_S13: + return "s13"; + case UNW_ARM_S14: + return "s14"; + case UNW_ARM_S15: + return "s15"; + case UNW_ARM_S16: + return "s16"; + case UNW_ARM_S17: + return "s17"; + case UNW_ARM_S18: + return "s18"; + case UNW_ARM_S19: + return "s19"; + case UNW_ARM_S20: + return "s20"; + case UNW_ARM_S21: + return "s21"; + case UNW_ARM_S22: + return "s22"; + case UNW_ARM_S23: + return "s23"; + case UNW_ARM_S24: + return "s24"; + case UNW_ARM_S25: + return "s25"; + case UNW_ARM_S26: + return "s26"; + case UNW_ARM_S27: + return "s27"; + case UNW_ARM_S28: + return "s28"; + case UNW_ARM_S29: + return "s29"; + case UNW_ARM_S30: + return "s30"; + case UNW_ARM_S31: + return "s31"; + case UNW_ARM_D0: + return "d0"; + case UNW_ARM_D1: + return "d1"; + case UNW_ARM_D2: + return "d2"; + case UNW_ARM_D3: + return "d3"; + case UNW_ARM_D4: + return "d4"; + case UNW_ARM_D5: + return "d5"; + case UNW_ARM_D6: + return "d6"; + case UNW_ARM_D7: + return "d7"; + case UNW_ARM_D8: + return "d8"; + case UNW_ARM_D9: + return "d9"; + case UNW_ARM_D10: + return "d10"; + case UNW_ARM_D11: + return "d11"; + case UNW_ARM_D12: + return "d12"; + case UNW_ARM_D13: + return "d13"; + case UNW_ARM_D14: + return "d14"; + case UNW_ARM_D15: + return "d15"; + case UNW_ARM_D16: + return "d16"; + case UNW_ARM_D17: + return "d17"; + case UNW_ARM_D18: + return "d18"; + case UNW_ARM_D19: + return "d19"; + case UNW_ARM_D20: + return "d20"; + case UNW_ARM_D21: + return "d21"; + case UNW_ARM_D22: + return "d22"; + case UNW_ARM_D23: + return "d23"; + case UNW_ARM_D24: + return "d24"; + case UNW_ARM_D25: + return "d25"; + case UNW_ARM_D26: + return "d26"; + case UNW_ARM_D27: + return "d27"; + case UNW_ARM_D28: + return "d28"; + case UNW_ARM_D29: + return "d29"; + case UNW_ARM_D30: + return "d30"; + case UNW_ARM_D31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_arm::validFloatRegister(int regNum) const { + // NOTE: Consider the intel MMX registers floating points so the + // __unw_get_fpreg can be used to transmit the 64-bit data back. + return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31)) +#if defined(__ARM_WMMX) + || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15)) +#endif + ; +} + +inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) { + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { + if (!_saved_vfp_d0_d15) { + _saved_vfp_d0_d15 = true; + if (_use_X_for_vfp_save) + saveVFPWithFSTMX(_vfp_d0_d15_pad); + else + saveVFPWithFSTMD(_vfp_d0_d15_pad); + } + return _vfp_d0_d15_pad[regNum - UNW_ARM_D0]; + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + if (!_saved_vfp_d16_d31) { + _saved_vfp_d16_d31 = true; + saveVFPv3(_vfp_d16_d31); + } + return _vfp_d16_d31[regNum - UNW_ARM_D16]; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + if (!_saved_iwmmx) { + _saved_iwmmx = true; + saveiWMMX(_iwmmx); + } + return _iwmmx[regNum - UNW_ARM_WR0]; + } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); +} + +inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) { + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) { + if (!_saved_vfp_d0_d15) { + _saved_vfp_d0_d15 = true; + if (_use_X_for_vfp_save) + saveVFPWithFSTMX(_vfp_d0_d15_pad); + else + saveVFPWithFSTMD(_vfp_d0_d15_pad); + } + _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value; + return; + } + + if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) { + if (!_saved_vfp_d16_d31) { + _saved_vfp_d16_d31 = true; + saveVFPv3(_vfp_d16_d31); + } + _vfp_d16_d31[regNum - UNW_ARM_D16] = value; + return; + } + +#if defined(__ARM_WMMX) + if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) { + if (!_saved_iwmmx) { + _saved_iwmmx = true; + saveiWMMX(_iwmmx); + } + _iwmmx[regNum - UNW_ARM_WR0] = value; + return; + } +#endif + + _LIBUNWIND_ABORT("Unknown ARM float register"); +} + +inline bool Registers_arm::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm::getVectorRegister(int) const { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} + +inline void Registers_arm::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} +#endif // _LIBUNWIND_TARGET_ARM + + +#if defined(_LIBUNWIND_TARGET_OR1K) +/// Registers_or1k holds the register state of a thread in an OpenRISC1000 +/// process. +class _LIBUNWIND_HIDDEN Registers_or1k { +public: + Registers_or1k(); + Registers_or1k(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; } + static int getArch() { return REGISTERS_OR1K; } + + uint64_t getSP() const { return _registers.__r[1]; } + void setSP(uint32_t value) { _registers.__r[1] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct or1k_thread_state_t { + unsigned int __r[32]; // r0-r31 + unsigned int __pc; // Program counter + unsigned int __epcr; // Program counter at exception + }; + + or1k_thread_state_t _registers; +}; + +inline Registers_or1k::Registers_or1k(const void *registers) { + static_assert((check_fit::does_fit), + "or1k registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_or1k::Registers_or1k() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_or1k::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_OR1K_R31) + return true; + if (regNum == UNW_OR1K_EPCR) + return true; + return false; +} + +inline uint32_t Registers_or1k::getRegister(int regNum) const { + if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) + return _registers.__r[regNum - UNW_OR1K_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[1]; + case UNW_OR1K_EPCR: + return _registers.__epcr; + } + _LIBUNWIND_ABORT("unsupported or1k register"); +} + +inline void Registers_or1k::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) { + _registers.__r[regNum - UNW_OR1K_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[1] = value; + return; + case UNW_OR1K_EPCR: + _registers.__epcr = value; + return; + } + _LIBUNWIND_ABORT("unsupported or1k register"); +} + +inline bool Registers_or1k::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_or1k::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("or1k float support not implemented"); +} + +inline void Registers_or1k::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("or1k float support not implemented"); +} + +inline bool Registers_or1k::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_or1k::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("or1k vector support not implemented"); +} + +inline void Registers_or1k::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("or1k vector support not implemented"); +} + +inline const char *Registers_or1k::getRegisterName(int regNum) { + switch (regNum) { + case UNW_OR1K_R0: + return "r0"; + case UNW_OR1K_R1: + return "r1"; + case UNW_OR1K_R2: + return "r2"; + case UNW_OR1K_R3: + return "r3"; + case UNW_OR1K_R4: + return "r4"; + case UNW_OR1K_R5: + return "r5"; + case UNW_OR1K_R6: + return "r6"; + case UNW_OR1K_R7: + return "r7"; + case UNW_OR1K_R8: + return "r8"; + case UNW_OR1K_R9: + return "r9"; + case UNW_OR1K_R10: + return "r10"; + case UNW_OR1K_R11: + return "r11"; + case UNW_OR1K_R12: + return "r12"; + case UNW_OR1K_R13: + return "r13"; + case UNW_OR1K_R14: + return "r14"; + case UNW_OR1K_R15: + return "r15"; + case UNW_OR1K_R16: + return "r16"; + case UNW_OR1K_R17: + return "r17"; + case UNW_OR1K_R18: + return "r18"; + case UNW_OR1K_R19: + return "r19"; + case UNW_OR1K_R20: + return "r20"; + case UNW_OR1K_R21: + return "r21"; + case UNW_OR1K_R22: + return "r22"; + case UNW_OR1K_R23: + return "r23"; + case UNW_OR1K_R24: + return "r24"; + case UNW_OR1K_R25: + return "r25"; + case UNW_OR1K_R26: + return "r26"; + case UNW_OR1K_R27: + return "r27"; + case UNW_OR1K_R28: + return "r28"; + case UNW_OR1K_R29: + return "r29"; + case UNW_OR1K_R30: + return "r30"; + case UNW_OR1K_R31: + return "r31"; + case UNW_OR1K_EPCR: + return "EPCR"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_OR1K + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) +/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS +/// process. +class _LIBUNWIND_HIDDEN Registers_mips_o32 { +public: + Registers_mips_o32(); + Registers_mips_o32(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_O32; } + + uint32_t getSP() const { return _registers.__r[29]; } + void setSP(uint32_t value) { _registers.__r[29] = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct mips_o32_thread_state_t { + uint32_t __r[32]; + uint32_t __pc; + uint32_t __hi; + uint32_t __lo; + }; + + mips_o32_thread_state_t _registers; +#ifdef __mips_hard_float + /// O32 with 32-bit floating point registers only uses half of this + /// space. However, using the same layout for 32-bit vs 64-bit + /// floating point registers results in a single context size for + /// O32 with hard float. + uint32_t _padding; + double _floats[32]; +#endif +}; + +inline Registers_mips_o32::Registers_mips_o32(const void *registers) { + static_assert((check_fit::does_fit), + "mips_o32 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_o32::Registers_mips_o32() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_o32::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#endif + // FIXME: DSP accumulator registers, MSA registers + return false; +} + +inline uint32_t Registers_mips_o32::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + return *p; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } +#if defined(__mips_hard_float) && __mips_fpr == 32 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) { + uint32_t *p; + + if (regNum % 2 == 0) + p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0]; + else + p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1; + *p = value; + return; + } +#endif + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_o32 register"); +} + +inline bool Registers_mips_o32::validFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#else + (void)regNum; +#endif + return false; +} + +inline double Registers_mips_o32::getFloatRegister(int regNum) const { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline void Registers_mips_o32::setFloatRegister(int regNum, + double value) { +#if defined(__mips_hard_float) && __mips_fpr == 64 + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("mips_o32 float support not implemented"); +#endif +} + +inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_o32 vector support not implemented"); +} + +inline const char *Registers_mips_o32::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_O32 + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) +/// Registers_mips_newabi holds the register state of a thread in a +/// MIPS process using NEWABI (the N32 or N64 ABIs). +class _LIBUNWIND_HIDDEN Registers_mips_newabi { +public: + Registers_mips_newabi(); + Registers_mips_newabi(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; } + static int getArch() { return REGISTERS_MIPS_NEWABI; } + + uint64_t getSP() const { return _registers.__r[29]; } + void setSP(uint64_t value) { _registers.__r[29] = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + +private: + struct mips_newabi_thread_state_t { + uint64_t __r[32]; + uint64_t __pc; + uint64_t __hi; + uint64_t __lo; + }; + + mips_newabi_thread_state_t _registers; +#ifdef __mips_hard_float + double _floats[32]; +#endif +}; + +inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) { + static_assert((check_fit::does_fit), + "mips_newabi registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_mips_newabi::Registers_mips_newabi() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_mips_newabi::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_MIPS_R31) + return true; +#if __mips_isa_rev != 6 + if (regNum == UNW_MIPS_HI) + return true; + if (regNum == UNW_MIPS_LO) + return true; +#endif + // FIXME: Hard float, DSP accumulator registers, MSA registers + return false; +} + +inline uint64_t Registers_mips_newabi::getRegister(int regNum) const { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) + return _registers.__r[regNum - UNW_MIPS_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__pc; + case UNW_REG_SP: + return _registers.__r[29]; + case UNW_MIPS_HI: + return _registers.__hi; + case UNW_MIPS_LO: + return _registers.__lo; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) { + _registers.__r[regNum - UNW_MIPS_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__pc = value; + return; + case UNW_REG_SP: + _registers.__r[29] = value; + return; + case UNW_MIPS_HI: + _registers.__hi = value; + return; + case UNW_MIPS_LO: + _registers.__lo = value; + return; + } + _LIBUNWIND_ABORT("unsupported mips_newabi register"); +} + +inline bool Registers_mips_newabi::validFloatRegister(int regNum) const { +#ifdef __mips_hard_float + if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) + return true; +#else + (void)regNum; +#endif + return false; +} + +inline double Registers_mips_newabi::getFloatRegister(int regNum) const { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_MIPS_F0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline void Registers_mips_newabi::setFloatRegister(int regNum, + double value) { +#ifdef __mips_hard_float + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_MIPS_F0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("mips_newabi float support not implemented"); +#endif +} + +inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("mips_newabi vector support not implemented"); +} + +inline const char *Registers_mips_newabi::getRegisterName(int regNum) { + switch (regNum) { + case UNW_MIPS_R0: + return "$0"; + case UNW_MIPS_R1: + return "$1"; + case UNW_MIPS_R2: + return "$2"; + case UNW_MIPS_R3: + return "$3"; + case UNW_MIPS_R4: + return "$4"; + case UNW_MIPS_R5: + return "$5"; + case UNW_MIPS_R6: + return "$6"; + case UNW_MIPS_R7: + return "$7"; + case UNW_MIPS_R8: + return "$8"; + case UNW_MIPS_R9: + return "$9"; + case UNW_MIPS_R10: + return "$10"; + case UNW_MIPS_R11: + return "$11"; + case UNW_MIPS_R12: + return "$12"; + case UNW_MIPS_R13: + return "$13"; + case UNW_MIPS_R14: + return "$14"; + case UNW_MIPS_R15: + return "$15"; + case UNW_MIPS_R16: + return "$16"; + case UNW_MIPS_R17: + return "$17"; + case UNW_MIPS_R18: + return "$18"; + case UNW_MIPS_R19: + return "$19"; + case UNW_MIPS_R20: + return "$20"; + case UNW_MIPS_R21: + return "$21"; + case UNW_MIPS_R22: + return "$22"; + case UNW_MIPS_R23: + return "$23"; + case UNW_MIPS_R24: + return "$24"; + case UNW_MIPS_R25: + return "$25"; + case UNW_MIPS_R26: + return "$26"; + case UNW_MIPS_R27: + return "$27"; + case UNW_MIPS_R28: + return "$28"; + case UNW_MIPS_R29: + return "$29"; + case UNW_MIPS_R30: + return "$30"; + case UNW_MIPS_R31: + return "$31"; + case UNW_MIPS_F0: + return "$f0"; + case UNW_MIPS_F1: + return "$f1"; + case UNW_MIPS_F2: + return "$f2"; + case UNW_MIPS_F3: + return "$f3"; + case UNW_MIPS_F4: + return "$f4"; + case UNW_MIPS_F5: + return "$f5"; + case UNW_MIPS_F6: + return "$f6"; + case UNW_MIPS_F7: + return "$f7"; + case UNW_MIPS_F8: + return "$f8"; + case UNW_MIPS_F9: + return "$f9"; + case UNW_MIPS_F10: + return "$f10"; + case UNW_MIPS_F11: + return "$f11"; + case UNW_MIPS_F12: + return "$f12"; + case UNW_MIPS_F13: + return "$f13"; + case UNW_MIPS_F14: + return "$f14"; + case UNW_MIPS_F15: + return "$f15"; + case UNW_MIPS_F16: + return "$f16"; + case UNW_MIPS_F17: + return "$f17"; + case UNW_MIPS_F18: + return "$f18"; + case UNW_MIPS_F19: + return "$f19"; + case UNW_MIPS_F20: + return "$f20"; + case UNW_MIPS_F21: + return "$f21"; + case UNW_MIPS_F22: + return "$f22"; + case UNW_MIPS_F23: + return "$f23"; + case UNW_MIPS_F24: + return "$f24"; + case UNW_MIPS_F25: + return "$f25"; + case UNW_MIPS_F26: + return "$f26"; + case UNW_MIPS_F27: + return "$f27"; + case UNW_MIPS_F28: + return "$f28"; + case UNW_MIPS_F29: + return "$f29"; + case UNW_MIPS_F30: + return "$f30"; + case UNW_MIPS_F31: + return "$f31"; + case UNW_MIPS_HI: + return "$hi"; + case UNW_MIPS_LO: + return "$lo"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_MIPS_NEWABI + +#if defined(_LIBUNWIND_TARGET_SPARC) +/// Registers_sparc holds the register state of a thread in a 32-bit Sparc +/// process. +class _LIBUNWIND_HIDDEN Registers_sparc { +public: + Registers_sparc(); + Registers_sparc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; } + static int getArch() { return REGISTERS_SPARC; } + + uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; } + void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; } + uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; } + void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; } + +private: + struct sparc_thread_state_t { + unsigned int __regs[32]; + }; + + sparc_thread_state_t _registers; +}; + +inline Registers_sparc::Registers_sparc(const void *registers) { + static_assert((check_fit::does_fit), + "sparc registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_sparc::Registers_sparc() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_sparc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_SPARC_I7) + return true; + return false; +} + +inline uint32_t Registers_sparc::getRegister(int regNum) const { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + return _registers.__regs[regNum]; + } + + switch (regNum) { + case UNW_REG_IP: + return _registers.__regs[UNW_SPARC_O7]; + case UNW_REG_SP: + return _registers.__regs[UNW_SPARC_O6]; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline void Registers_sparc::setRegister(int regNum, uint32_t value) { + if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) { + _registers.__regs[regNum] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__regs[UNW_SPARC_O7] = value; + return; + case UNW_REG_SP: + _registers.__regs[UNW_SPARC_O6] = value; + return; + } + _LIBUNWIND_ABORT("unsupported sparc register"); +} + +inline bool Registers_sparc::validFloatRegister(int) const { return false; } + +inline double Registers_sparc::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline void Registers_sparc::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no Sparc float registers"); +} + +inline bool Registers_sparc::validVectorRegister(int) const { return false; } + +inline v128 Registers_sparc::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline void Registers_sparc::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no Sparc vector registers"); +} + +inline const char *Registers_sparc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_SPARC_G0: + return "g0"; + case UNW_SPARC_G1: + return "g1"; + case UNW_SPARC_G2: + return "g2"; + case UNW_SPARC_G3: + return "g3"; + case UNW_SPARC_G4: + return "g4"; + case UNW_SPARC_G5: + return "g5"; + case UNW_SPARC_G6: + return "g6"; + case UNW_SPARC_G7: + return "g7"; + case UNW_SPARC_O0: + return "o0"; + case UNW_SPARC_O1: + return "o1"; + case UNW_SPARC_O2: + return "o2"; + case UNW_SPARC_O3: + return "o3"; + case UNW_SPARC_O4: + return "o4"; + case UNW_SPARC_O5: + return "o5"; + case UNW_REG_SP: + case UNW_SPARC_O6: + return "sp"; + case UNW_SPARC_O7: + return "o7"; + case UNW_SPARC_L0: + return "l0"; + case UNW_SPARC_L1: + return "l1"; + case UNW_SPARC_L2: + return "l2"; + case UNW_SPARC_L3: + return "l3"; + case UNW_SPARC_L4: + return "l4"; + case UNW_SPARC_L5: + return "l5"; + case UNW_SPARC_L6: + return "l6"; + case UNW_SPARC_L7: + return "l7"; + case UNW_SPARC_I0: + return "i0"; + case UNW_SPARC_I1: + return "i1"; + case UNW_SPARC_I2: + return "i2"; + case UNW_SPARC_I3: + return "i3"; + case UNW_SPARC_I4: + return "i4"; + case UNW_SPARC_I5: + return "i5"; + case UNW_SPARC_I6: + return "fp"; + case UNW_SPARC_I7: + return "i7"; + default: + return "unknown register"; + } +} +#endif // _LIBUNWIND_TARGET_SPARC + +#if defined(_LIBUNWIND_TARGET_HEXAGON) +/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6 +/// process. +class _LIBUNWIND_HIDDEN Registers_hexagon { +public: + Registers_hexagon(); + Registers_hexagon(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; } + static int getArch() { return REGISTERS_HEXAGON; } + + uint32_t getSP() const { return _registers.__r[UNW_HEXAGON_R29]; } + void setSP(uint32_t value) { _registers.__r[UNW_HEXAGON_R29] = value; } + uint32_t getIP() const { return _registers.__r[UNW_HEXAGON_PC]; } + void setIP(uint32_t value) { _registers.__r[UNW_HEXAGON_PC] = value; } + +private: + struct hexagon_thread_state_t { + unsigned int __r[35]; + }; + + hexagon_thread_state_t _registers; +}; + +inline Registers_hexagon::Registers_hexagon(const void *registers) { + static_assert((check_fit::does_fit), + "hexagon registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); +} + +inline Registers_hexagon::Registers_hexagon() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_hexagon::validRegister(int regNum) const { + if (regNum <= UNW_HEXAGON_R31) + return true; + return false; +} + +inline uint32_t Registers_hexagon::getRegister(int regNum) const { + if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) + return _registers.__r[regNum - UNW_HEXAGON_R0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__r[UNW_HEXAGON_PC]; + case UNW_REG_SP: + return _registers.__r[UNW_HEXAGON_R29]; + } + _LIBUNWIND_ABORT("unsupported hexagon register"); +} + +inline void Registers_hexagon::setRegister(int regNum, uint32_t value) { + if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) { + _registers.__r[regNum - UNW_HEXAGON_R0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__r[UNW_HEXAGON_PC] = value; + return; + case UNW_REG_SP: + _registers.__r[UNW_HEXAGON_R29] = value; + return; + } + _LIBUNWIND_ABORT("unsupported hexagon register"); +} + +inline bool Registers_hexagon::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_hexagon::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("hexagon float support not implemented"); +} + +inline void Registers_hexagon::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("hexagon float support not implemented"); +} + +inline bool Registers_hexagon::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_hexagon::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("hexagon vector support not implemented"); +} + +inline void Registers_hexagon::setVectorRegister(int /* regNum */, v128 /* value */) { + _LIBUNWIND_ABORT("hexagon vector support not implemented"); +} + +inline const char *Registers_hexagon::getRegisterName(int regNum) { + switch (regNum) { + case UNW_HEXAGON_R0: + return "r0"; + case UNW_HEXAGON_R1: + return "r1"; + case UNW_HEXAGON_R2: + return "r2"; + case UNW_HEXAGON_R3: + return "r3"; + case UNW_HEXAGON_R4: + return "r4"; + case UNW_HEXAGON_R5: + return "r5"; + case UNW_HEXAGON_R6: + return "r6"; + case UNW_HEXAGON_R7: + return "r7"; + case UNW_HEXAGON_R8: + return "r8"; + case UNW_HEXAGON_R9: + return "r9"; + case UNW_HEXAGON_R10: + return "r10"; + case UNW_HEXAGON_R11: + return "r11"; + case UNW_HEXAGON_R12: + return "r12"; + case UNW_HEXAGON_R13: + return "r13"; + case UNW_HEXAGON_R14: + return "r14"; + case UNW_HEXAGON_R15: + return "r15"; + case UNW_HEXAGON_R16: + return "r16"; + case UNW_HEXAGON_R17: + return "r17"; + case UNW_HEXAGON_R18: + return "r18"; + case UNW_HEXAGON_R19: + return "r19"; + case UNW_HEXAGON_R20: + return "r20"; + case UNW_HEXAGON_R21: + return "r21"; + case UNW_HEXAGON_R22: + return "r22"; + case UNW_HEXAGON_R23: + return "r23"; + case UNW_HEXAGON_R24: + return "r24"; + case UNW_HEXAGON_R25: + return "r25"; + case UNW_HEXAGON_R26: + return "r26"; + case UNW_HEXAGON_R27: + return "r27"; + case UNW_HEXAGON_R28: + return "r28"; + case UNW_HEXAGON_R29: + return "r29"; + case UNW_HEXAGON_R30: + return "r30"; + case UNW_HEXAGON_R31: + return "r31"; + default: + return "unknown register"; + } + +} +#endif // _LIBUNWIND_TARGET_HEXAGON + + +#if defined(_LIBUNWIND_TARGET_RISCV) +/// Registers_riscv holds the register state of a thread in a RISC-V +/// process. + +// This check makes it safe when LIBUNWIND_ENABLE_CROSS_UNWINDING enabled. +# ifdef __riscv +# if __riscv_xlen == 32 +typedef uint32_t reg_t; +# elif __riscv_xlen == 64 +typedef uint64_t reg_t; +# else +# error "Unsupported __riscv_xlen" +# endif + +# if defined(__riscv_flen) +# if __riscv_flen == 64 +typedef double fp_t; +# elif __riscv_flen == 32 +typedef float fp_t; +# else +# error "Unsupported __riscv_flen" +# endif +# else +// This is just for supressing undeclared error of fp_t. +typedef double fp_t; +# endif +# else +// Use Max possible width when cross unwinding +typedef uint64_t reg_t; +typedef double fp_t; +# define __riscv_xlen 64 +# define __riscv_flen 64 +#endif + +/// Registers_riscv holds the register state of a thread. +class _LIBUNWIND_HIDDEN Registers_riscv { +public: + Registers_riscv(); + Registers_riscv(const void *registers); + + bool validRegister(int num) const; + reg_t getRegister(int num) const; + void setRegister(int num, reg_t value); + bool validFloatRegister(int num) const; + fp_t getFloatRegister(int num) const; + void setFloatRegister(int num, fp_t value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; } + static int getArch() { return REGISTERS_RISCV; } + + reg_t getSP() const { return _registers[2]; } + void setSP(reg_t value) { _registers[2] = value; } + reg_t getIP() const { return _registers[0]; } + void setIP(reg_t value) { _registers[0] = value; } + +private: + // _registers[0] holds the pc + reg_t _registers[32]; +# if defined(__riscv_flen) + fp_t _floats[32]; +# endif +}; + +inline Registers_riscv::Registers_riscv(const void *registers) { + static_assert((check_fit::does_fit), + "riscv registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); +# if __riscv_xlen == 32 + static_assert(sizeof(_registers) == 0x80, + "expected float registers to be at offset 128"); +# elif __riscv_xlen == 64 + static_assert(sizeof(_registers) == 0x100, + "expected float registers to be at offset 256"); +# else +# error "Unexpected float registers." +# endif + +# if defined(__riscv_flen) + memcpy(_floats, + static_cast(registers) + sizeof(_registers), + sizeof(_floats)); +# endif +} + +inline Registers_riscv::Registers_riscv() { + memset(&_registers, 0, sizeof(_registers)); +# if defined(__riscv_flen) + memset(&_floats, 0, sizeof(_floats)); +# endif +} + +inline bool Registers_riscv::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +} + +inline reg_t Registers_riscv::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return _registers[0]; + if (regNum == UNW_REG_SP) + return _registers[2]; + if (regNum == UNW_RISCV_X0) + return 0; + if ((regNum > 0) && (regNum < 32)) + return _registers[regNum]; + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline void Registers_riscv::setRegister(int regNum, reg_t value) { + if (regNum == UNW_REG_IP) + _registers[0] = value; + else if (regNum == UNW_REG_SP) + _registers[2] = value; + else if (regNum == UNW_RISCV_X0) + /* x0 is hardwired to zero */ + return; + else if ((regNum > 0) && (regNum < 32)) + _registers[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported riscv register"); +} + +inline const char *Registers_riscv::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_RISCV_X0: + return "zero"; + case UNW_RISCV_X1: + return "ra"; + case UNW_RISCV_X2: + return "sp"; + case UNW_RISCV_X3: + return "gp"; + case UNW_RISCV_X4: + return "tp"; + case UNW_RISCV_X5: + return "t0"; + case UNW_RISCV_X6: + return "t1"; + case UNW_RISCV_X7: + return "t2"; + case UNW_RISCV_X8: + return "s0"; + case UNW_RISCV_X9: + return "s1"; + case UNW_RISCV_X10: + return "a0"; + case UNW_RISCV_X11: + return "a1"; + case UNW_RISCV_X12: + return "a2"; + case UNW_RISCV_X13: + return "a3"; + case UNW_RISCV_X14: + return "a4"; + case UNW_RISCV_X15: + return "a5"; + case UNW_RISCV_X16: + return "a6"; + case UNW_RISCV_X17: + return "a7"; + case UNW_RISCV_X18: + return "s2"; + case UNW_RISCV_X19: + return "s3"; + case UNW_RISCV_X20: + return "s4"; + case UNW_RISCV_X21: + return "s5"; + case UNW_RISCV_X22: + return "s6"; + case UNW_RISCV_X23: + return "s7"; + case UNW_RISCV_X24: + return "s8"; + case UNW_RISCV_X25: + return "s9"; + case UNW_RISCV_X26: + return "s10"; + case UNW_RISCV_X27: + return "s11"; + case UNW_RISCV_X28: + return "t3"; + case UNW_RISCV_X29: + return "t4"; + case UNW_RISCV_X30: + return "t5"; + case UNW_RISCV_X31: + return "t6"; + case UNW_RISCV_F0: + return "ft0"; + case UNW_RISCV_F1: + return "ft1"; + case UNW_RISCV_F2: + return "ft2"; + case UNW_RISCV_F3: + return "ft3"; + case UNW_RISCV_F4: + return "ft4"; + case UNW_RISCV_F5: + return "ft5"; + case UNW_RISCV_F6: + return "ft6"; + case UNW_RISCV_F7: + return "ft7"; + case UNW_RISCV_F8: + return "fs0"; + case UNW_RISCV_F9: + return "fs1"; + case UNW_RISCV_F10: + return "fa0"; + case UNW_RISCV_F11: + return "fa1"; + case UNW_RISCV_F12: + return "fa2"; + case UNW_RISCV_F13: + return "fa3"; + case UNW_RISCV_F14: + return "fa4"; + case UNW_RISCV_F15: + return "fa5"; + case UNW_RISCV_F16: + return "fa6"; + case UNW_RISCV_F17: + return "fa7"; + case UNW_RISCV_F18: + return "fs2"; + case UNW_RISCV_F19: + return "fs3"; + case UNW_RISCV_F20: + return "fs4"; + case UNW_RISCV_F21: + return "fs5"; + case UNW_RISCV_F22: + return "fs6"; + case UNW_RISCV_F23: + return "fs7"; + case UNW_RISCV_F24: + return "fs8"; + case UNW_RISCV_F25: + return "fs9"; + case UNW_RISCV_F26: + return "fs10"; + case UNW_RISCV_F27: + return "fs11"; + case UNW_RISCV_F28: + return "ft8"; + case UNW_RISCV_F29: + return "ft9"; + case UNW_RISCV_F30: + return "ft10"; + case UNW_RISCV_F31: + return "ft11"; + default: + return "unknown register"; + } +} + +inline bool Registers_riscv::validFloatRegister(int regNum) const { +# if defined(__riscv_flen) + if (regNum < UNW_RISCV_F0) + return false; + if (regNum > UNW_RISCV_F31) + return false; + return true; +# else + (void)regNum; + return false; +# endif +} + +inline fp_t Registers_riscv::getFloatRegister(int regNum) const { +# if defined(__riscv_flen) + assert(validFloatRegister(regNum)); + return _floats[regNum - UNW_RISCV_F0]; +# else + (void)regNum; + _LIBUNWIND_ABORT("libunwind not built with float support"); +# endif +} + +inline void Registers_riscv::setFloatRegister(int regNum, fp_t value) { +# if defined(__riscv_flen) + assert(validFloatRegister(regNum)); + _floats[regNum - UNW_RISCV_F0] = value; +# else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("libunwind not built with float support"); +# endif +} + +inline bool Registers_riscv::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_riscv::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} + +inline void Registers_riscv::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no riscv vector register support yet"); +} +#endif // _LIBUNWIND_TARGET_RISCV + +#if defined(_LIBUNWIND_TARGET_VE) +/// Registers_ve holds the register state of a thread in a VE process. +class _LIBUNWIND_HIDDEN Registers_ve { +public: + Registers_ve(); + Registers_ve(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + static const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE; } + static int getArch() { return REGISTERS_VE; } + + uint64_t getSP() const { return _registers.__s[11]; } + void setSP(uint64_t value) { _registers.__s[11] = value; } + uint64_t getIP() const { return _registers.__ic; } + void setIP(uint64_t value) { _registers.__ic = value; } + +private: + // FIXME: Need to store not only scalar registers but also vector and vector + // mask registers. VEOS uses mcontext_t defined in ucontext.h. It takes + // 524288 bytes (65536*8 bytes), though. Currently, we use libunwind for + // SjLj exception support only, so Registers_ve is not implemented completely. + struct ve_thread_state_t { + uint64_t __s[64]; // s0-s64 + uint64_t __ic; // Instruction counter (IC) + uint64_t __vixr; // Vector Index Register + uint64_t __vl; // Vector Length Register + }; + + ve_thread_state_t _registers; // total 67 registers + + // Currently no vector register is preserved. +}; + +inline Registers_ve::Registers_ve(const void *registers) { + static_assert((check_fit::does_fit), + "ve registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + static_assert(sizeof(_registers) == 536, + "expected vector register offset to be 536"); +} + +inline Registers_ve::Registers_ve() { + memset(&_registers, 0, sizeof(_registers)); +} + +inline bool Registers_ve::validRegister(int regNum) const { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) + return true; + + switch (regNum) { + case UNW_REG_IP: + case UNW_REG_SP: + case UNW_VE_VIXR: + case UNW_VE_VL: + return true; + default: + return false; + } +} + +inline uint64_t Registers_ve::getRegister(int regNum) const { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) + return _registers.__s[regNum - UNW_VE_S0]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__ic; + case UNW_REG_SP: + return _registers.__s[11]; + case UNW_VE_VIXR: + return _registers.__vixr; + case UNW_VE_VL: + return _registers.__vl; + } + _LIBUNWIND_ABORT("unsupported ve register"); +} + +inline void Registers_ve::setRegister(int regNum, uint64_t value) { + if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) { + _registers.__s[regNum - UNW_VE_S0] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__ic = value; + return; + case UNW_REG_SP: + _registers.__s[11] = value; + return; + case UNW_VE_VIXR: + _registers.__vixr = value; + return; + case UNW_VE_VL: + _registers.__vl = value; + return; + } + _LIBUNWIND_ABORT("unsupported ve register"); +} + +inline bool Registers_ve::validFloatRegister(int /* regNum */) const { + return false; +} + +inline double Registers_ve::getFloatRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("VE doesn't have float registers"); +} + +inline void Registers_ve::setFloatRegister(int /* regNum */, + double /* value */) { + _LIBUNWIND_ABORT("VE doesn't have float registers"); +} + +inline bool Registers_ve::validVectorRegister(int /* regNum */) const { + return false; +} + +inline v128 Registers_ve::getVectorRegister(int /* regNum */) const { + _LIBUNWIND_ABORT("VE vector support not implemented"); +} + +inline void Registers_ve::setVectorRegister(int /* regNum */, + v128 /* value */) { + _LIBUNWIND_ABORT("VE vector support not implemented"); +} + +inline const char *Registers_ve::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_VE_VIXR: + return "vixr"; + case UNW_VE_VL: + return "vl"; + case UNW_VE_S0: + return "s0"; + case UNW_VE_S1: + return "s1"; + case UNW_VE_S2: + return "s2"; + case UNW_VE_S3: + return "s3"; + case UNW_VE_S4: + return "s4"; + case UNW_VE_S5: + return "s5"; + case UNW_VE_S6: + return "s6"; + case UNW_VE_S7: + return "s7"; + case UNW_VE_S8: + return "s8"; + case UNW_VE_S9: + return "s9"; + case UNW_VE_S10: + return "s10"; + case UNW_VE_S11: + return "s11"; + case UNW_VE_S12: + return "s12"; + case UNW_VE_S13: + return "s13"; + case UNW_VE_S14: + return "s14"; + case UNW_VE_S15: + return "s15"; + case UNW_VE_S16: + return "s16"; + case UNW_VE_S17: + return "s17"; + case UNW_VE_S18: + return "s18"; + case UNW_VE_S19: + return "s19"; + case UNW_VE_S20: + return "s20"; + case UNW_VE_S21: + return "s21"; + case UNW_VE_S22: + return "s22"; + case UNW_VE_S23: + return "s23"; + case UNW_VE_S24: + return "s24"; + case UNW_VE_S25: + return "s25"; + case UNW_VE_S26: + return "s26"; + case UNW_VE_S27: + return "s27"; + case UNW_VE_S28: + return "s28"; + case UNW_VE_S29: + return "s29"; + case UNW_VE_S30: + return "s30"; + case UNW_VE_S31: + return "s31"; + case UNW_VE_S32: + return "s32"; + case UNW_VE_S33: + return "s33"; + case UNW_VE_S34: + return "s34"; + case UNW_VE_S35: + return "s35"; + case UNW_VE_S36: + return "s36"; + case UNW_VE_S37: + return "s37"; + case UNW_VE_S38: + return "s38"; + case UNW_VE_S39: + return "s39"; + case UNW_VE_S40: + return "s40"; + case UNW_VE_S41: + return "s41"; + case UNW_VE_S42: + return "s42"; + case UNW_VE_S43: + return "s43"; + case UNW_VE_S44: + return "s44"; + case UNW_VE_S45: + return "s45"; + case UNW_VE_S46: + return "s46"; + case UNW_VE_S47: + return "s47"; + case UNW_VE_S48: + return "s48"; + case UNW_VE_S49: + return "s49"; + case UNW_VE_S50: + return "s50"; + case UNW_VE_S51: + return "s51"; + case UNW_VE_S52: + return "s52"; + case UNW_VE_S53: + return "s53"; + case UNW_VE_S54: + return "s54"; + case UNW_VE_S55: + return "s55"; + case UNW_VE_S56: + return "s56"; + case UNW_VE_S57: + return "s57"; + case UNW_VE_S58: + return "s58"; + case UNW_VE_S59: + return "s59"; + case UNW_VE_S60: + return "s60"; + case UNW_VE_S61: + return "s61"; + case UNW_VE_S62: + return "s62"; + case UNW_VE_S63: + return "s63"; + case UNW_VE_V0: + return "v0"; + case UNW_VE_V1: + return "v1"; + case UNW_VE_V2: + return "v2"; + case UNW_VE_V3: + return "v3"; + case UNW_VE_V4: + return "v4"; + case UNW_VE_V5: + return "v5"; + case UNW_VE_V6: + return "v6"; + case UNW_VE_V7: + return "v7"; + case UNW_VE_V8: + return "v8"; + case UNW_VE_V9: + return "v9"; + case UNW_VE_V10: + return "v10"; + case UNW_VE_V11: + return "v11"; + case UNW_VE_V12: + return "v12"; + case UNW_VE_V13: + return "v13"; + case UNW_VE_V14: + return "v14"; + case UNW_VE_V15: + return "v15"; + case UNW_VE_V16: + return "v16"; + case UNW_VE_V17: + return "v17"; + case UNW_VE_V18: + return "v18"; + case UNW_VE_V19: + return "v19"; + case UNW_VE_V20: + return "v20"; + case UNW_VE_V21: + return "v21"; + case UNW_VE_V22: + return "v22"; + case UNW_VE_V23: + return "v23"; + case UNW_VE_V24: + return "v24"; + case UNW_VE_V25: + return "v25"; + case UNW_VE_V26: + return "v26"; + case UNW_VE_V27: + return "v27"; + case UNW_VE_V28: + return "v28"; + case UNW_VE_V29: + return "v29"; + case UNW_VE_V30: + return "v30"; + case UNW_VE_V31: + return "v31"; + case UNW_VE_V32: + return "v32"; + case UNW_VE_V33: + return "v33"; + case UNW_VE_V34: + return "v34"; + case UNW_VE_V35: + return "v35"; + case UNW_VE_V36: + return "v36"; + case UNW_VE_V37: + return "v37"; + case UNW_VE_V38: + return "v38"; + case UNW_VE_V39: + return "v39"; + case UNW_VE_V40: + return "v40"; + case UNW_VE_V41: + return "v41"; + case UNW_VE_V42: + return "v42"; + case UNW_VE_V43: + return "v43"; + case UNW_VE_V44: + return "v44"; + case UNW_VE_V45: + return "v45"; + case UNW_VE_V46: + return "v46"; + case UNW_VE_V47: + return "v47"; + case UNW_VE_V48: + return "v48"; + case UNW_VE_V49: + return "v49"; + case UNW_VE_V50: + return "v50"; + case UNW_VE_V51: + return "v51"; + case UNW_VE_V52: + return "v52"; + case UNW_VE_V53: + return "v53"; + case UNW_VE_V54: + return "v54"; + case UNW_VE_V55: + return "v55"; + case UNW_VE_V56: + return "v56"; + case UNW_VE_V57: + return "v57"; + case UNW_VE_V58: + return "v58"; + case UNW_VE_V59: + return "v59"; + case UNW_VE_V60: + return "v60"; + case UNW_VE_V61: + return "v61"; + case UNW_VE_V62: + return "v62"; + case UNW_VE_V63: + return "v63"; + case UNW_VE_VM0: + return "vm0"; + case UNW_VE_VM1: + return "vm1"; + case UNW_VE_VM2: + return "vm2"; + case UNW_VE_VM3: + return "vm3"; + case UNW_VE_VM4: + return "vm4"; + case UNW_VE_VM5: + return "vm5"; + case UNW_VE_VM6: + return "vm6"; + case UNW_VE_VM7: + return "vm7"; + case UNW_VE_VM8: + return "vm8"; + case UNW_VE_VM9: + return "vm9"; + case UNW_VE_VM10: + return "vm10"; + case UNW_VE_VM11: + return "vm11"; + case UNW_VE_VM12: + return "vm12"; + case UNW_VE_VM13: + return "vm13"; + case UNW_VE_VM14: + return "vm14"; + case UNW_VE_VM15: + return "vm15"; + } + return "unknown register"; +} +#endif // _LIBUNWIND_TARGET_VE + +} // namespace libunwind + +#endif // __REGISTERS_HPP__ diff --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp new file mode 100644 index 0000000000..a564fd5240 --- /dev/null +++ b/libunwind/src/Unwind-EHABI.cpp @@ -0,0 +1,1141 @@ +//===--------------------------- Unwind-EHABI.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements ARM zero-cost C++ exceptions +// +//===----------------------------------------------------------------------===// + +#include "Unwind-EHABI.h" + +#if defined(_LIBUNWIND_ARM_EHABI) + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "libunwind.h" +#include "libunwind_ext.h" +#include "unwind.h" + +namespace { + +// Strange order: take words in order, but inside word, take from most to least +// signinficant byte. +uint8_t getByte(const uint32_t* data, size_t offset) { + const uint8_t* byteData = reinterpret_cast(data); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return byteData[offset]; +#else +#error "Unable to determine endianess" +#endif +} + +const char* getNextWord(const char* data, uint32_t* out) { + *out = *reinterpret_cast(data); + return data + 4; +} + +const char* getNextNibble(const char* data, uint32_t* out) { + *out = *reinterpret_cast(data); + return data + 2; +} + +struct Descriptor { + // See # 9.2 + typedef enum { + SU16 = 0, // Short descriptor, 16-bit entries + LU16 = 1, // Long descriptor, 16-bit entries + LU32 = 3, // Long descriptor, 32-bit entries + RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, + RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, + RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 + } Format; + + // See # 9.2 + typedef enum { + CLEANUP = 0x0, + FUNC = 0x1, + CATCH = 0x2, + INVALID = 0x4 + } Kind; +}; + +_Unwind_Reason_Code ProcessDescriptors( + _Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context, + Descriptor::Format format, + const char* descriptorStart, + uint32_t flags) { + + // EHT is inlined in the index using compact form. No descriptors. #5 + if (flags & 0x1) + return _URC_CONTINUE_UNWIND; + + // TODO: We should check the state here, and determine whether we need to + // perform phase1 or phase2 unwinding. + (void)state; + + const char* descriptor = descriptorStart; + uint32_t descriptorWord; + getNextWord(descriptor, &descriptorWord); + while (descriptorWord) { + // Read descriptor based on # 9.2. + uint32_t length; + uint32_t offset; + switch (format) { + case Descriptor::LU32: + descriptor = getNextWord(descriptor, &length); + descriptor = getNextWord(descriptor, &offset); + break; + case Descriptor::LU16: + descriptor = getNextNibble(descriptor, &length); + descriptor = getNextNibble(descriptor, &offset); + break; + default: + assert(false); + return _URC_FAILURE; + } + + // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. + Descriptor::Kind kind = + static_cast((length & 0x1) | ((offset & 0x1) << 1)); + + // Clear off flag from last bit. + length &= ~1u; + offset &= ~1u; + uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; + uintptr_t scopeEnd = scopeStart + length; + uintptr_t pc = _Unwind_GetIP(context); + bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); + + switch (kind) { + case Descriptor::CLEANUP: { + // TODO(ajwong): Handle cleanup descriptors. + break; + } + case Descriptor::FUNC: { + // TODO(ajwong): Handle function descriptors. + break; + } + case Descriptor::CATCH: { + // Catch descriptors require gobbling one more word. + uint32_t landing_pad; + descriptor = getNextWord(descriptor, &landing_pad); + + if (isInScope) { + // TODO(ajwong): This is only phase1 compatible logic. Implement + // phase2. + landing_pad = signExtendPrel31(landing_pad & ~0x80000000); + if (landing_pad == 0xffffffff) { + return _URC_HANDLER_FOUND; + } else if (landing_pad == 0xfffffffe) { + return _URC_FAILURE; + } else { + /* + bool is_reference_type = landing_pad & 0x80000000; + void* matched_object; + if (__cxxabiv1::__cxa_type_match( + ucbp, reinterpret_cast(landing_pad), + is_reference_type, + &matched_object) != __cxxabiv1::ctm_failed) + return _URC_HANDLER_FOUND; + */ + _LIBUNWIND_ABORT("Type matching not implemented"); + } + } + break; + } + default: + _LIBUNWIND_ABORT("Invalid descriptor kind found."); + } + + getNextWord(descriptor, &descriptorWord); + } + + return _URC_CONTINUE_UNWIND; +} + +static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context) { + // Read the compact model EHT entry's header # 6.3 + const uint32_t* unwindingData = ucbp->pr_cache.ehtp; + assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); + Descriptor::Format format = + static_cast((*unwindingData & 0x0f000000) >> 24); + + const char *lsda = + reinterpret_cast(_Unwind_GetLanguageSpecificData(context)); + + // Handle descriptors before unwinding so they are processed in the context + // of the correct stack frame. + _Unwind_Reason_Code result = + ProcessDescriptors(state, ucbp, context, format, lsda, + ucbp->pr_cache.additional); + + if (result != _URC_CONTINUE_UNWIND) + return result; + + if (__unw_step(reinterpret_cast(context)) != UNW_STEP_SUCCESS) + return _URC_FAILURE; + return _URC_CONTINUE_UNWIND; +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / +// _UVRSD_UINT32. +uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { + return ((1U << (count_minus_one + 1)) - 1) << start; +} + +// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / +// _UVRSD_DOUBLE. +uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { + return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1); +} + +} // end anonymous namespace + +/** + * Decodes an EHT entry. + * + * @param data Pointer to EHT. + * @param[out] off Offset from return value (in bytes) to begin interpretation. + * @param[out] len Number of bytes in unwind code. + * @return Pointer to beginning of unwind code. + */ +extern "C" const uint32_t* +decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { + if ((*data & 0x80000000) == 0) { + // 6.2: Generic Model + // + // EHT entry is a prel31 pointing to the PR, followed by data understood + // only by the personality routine. Fortunately, all existing assembler + // implementations, including GNU assembler, LLVM integrated assembler, + // and ARM assembler, assume that the unwind opcodes come after the + // personality rountine address. + *off = 1; // First byte is size data. + *len = (((data[1] >> 24) & 0xff) + 1) * 4; + data++; // Skip the first word, which is the prel31 offset. + } else { + // 6.3: ARM Compact Model + // + // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded + // by format: + Descriptor::Format format = + static_cast((*data & 0x0f000000) >> 24); + switch (format) { + case Descriptor::SU16: + *len = 4; + *off = 1; + break; + case Descriptor::LU16: + case Descriptor::LU32: + *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); + *off = 2; + break; + default: + return nullptr; + } + } + return data; +} + +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, + size_t offset, size_t len) { + bool wrotePC = false; + bool finish = false; + while (offset < len && !finish) { + uint8_t byte = getByte(data, offset++); + if ((byte & 0x80) == 0) { + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + if (byte & 0x40) + sp -= (((uint32_t)byte & 0x3f) << 2) + 4; + else + sp += ((uint32_t)byte << 2) + 4; + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + } else { + switch (byte & 0xf0) { + case 0x80: { + if (offset >= len) + return _URC_FAILURE; + uint32_t registers = + (((uint32_t)byte & 0x0f) << 12) | + (((uint32_t)getByte(data, offset++)) << 4); + if (!registers) + return _URC_FAILURE; + if (registers & (1 << 15)) + wrotePC = true; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0x90: { + uint8_t reg = byte & 0x0f; + if (reg == 13 || reg == 15) + return _URC_FAILURE; + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, + _UVRSD_UINT32, &sp); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xa0: { + uint32_t registers = RegisterMask(4, byte & 0x07); + if (byte & 0x08) + registers |= 1 << 14; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb0: { + switch (byte) { + case 0xb0: + finish = true; + break; + case 0xb1: { + if (offset >= len) + return _URC_FAILURE; + uint8_t registers = getByte(data, offset++); + if (registers & 0xf0 || !registers) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); + break; + } + case 0xb2: { + uint32_t addend = 0; + uint32_t shift = 0; + // This decodes a uleb128 value. + while (true) { + if (offset >= len) + return _URC_FAILURE; + uint32_t v = getByte(data, offset++); + addend |= (v & 0x7f) << shift; + if ((v & 0x80) == 0) + break; + shift += 7; + } + uint32_t sp; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + sp += 0x204 + (addend << 2); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + break; + } + case 0xb3: { + uint8_t v = getByte(data, offset++); + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(static_cast(v >> 4), + v & 0x0f), _UVRSD_VFPX); + break; + } + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + return _URC_FAILURE; + default: + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(8, byte & 0x07), _UVRSD_VFPX); + break; + } + break; + } + case 0xc0: { + switch (byte) { +#if defined(__ARM_WMMX) + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); + break; + case 0xc6: { + uint8_t v = getByte(data, offset++); + uint8_t start = static_cast(v >> 4); + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 16) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXD, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + case 0xc7: { + uint8_t v = getByte(data, offset++); + if (!v || v & 0xf0) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); + break; + } +#endif + case 0xc8: + case 0xc9: { + uint8_t v = getByte(data, offset++); + uint8_t start = + static_cast(((byte == 0xc8) ? 16 : 0) + (v >> 4)); + uint8_t count_minus_one = v & 0xf; + if (start + count_minus_one >= 32) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, + RegisterRange(start, count_minus_one), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + break; + } + case 0xd0: { + if (byte & 0x08) + return _URC_FAILURE; + _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), + _UVRSD_DOUBLE); + break; + } + default: + return _URC_FAILURE; + } + } + } + if (!wrotePC) { + uint32_t lr; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); + } + return _URC_CONTINUE_UNWIND; +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, + _Unwind_Context *context) { + return unwindOneFrame(state, ucbp, context); +} + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during + // phase 1 and then restoring it to the "primary VRS" for phase 2. The + // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. + // In this implementation, the phases don't share the VRS backing store. + // Instead, they are passed the original |uc| and they create a new VRS + // from scratch thus achieving the same effect. + __unw_init_local(cursor, uc); + + // Walk each frame looking for a place to stop. + for (bool handlerNotFound = true; handlerNotFound;) { + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE1_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + static_cast(exception_object), pc, + frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } +#endif + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(long)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p", + static_cast(exception_object), + reinterpret_cast(reinterpret_cast(p))); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " + "additional %x", + static_cast(exception_object), personalityResult, + exception_object->pr_cache.fnstart, + static_cast(exception_object->pr_cache.ehtp), + exception_object->pr_cache.additional); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + handlerNotFound = false; + // p should have initialized barrier_cache. EHABI #7.3.5 + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", + static_cast(exception_object)); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", + static_cast(exception_object)); + // continue unwinding + break; + + // EHABI #7.3.3 + case _URC_FAILURE: + return _URC_FAILURE; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + +static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, + bool resume) { + // See comment at the start of unwind_phase1 regarding VRS integrity. + __unw_init_local(cursor, uc); + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + static_cast(exception_object)); + int frame_count = 0; + + // Walk each frame until we reach where search phase said to stop. + while (true) { + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException or _Unwind_Resume). + // + // Resume only ever makes sense for 1 frame. + _Unwind_State state = + resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; + if (resume && frame_count == 1) { + // On a resume, first unwind the _Unwind_Resume() frame. The next frame + // is now the landing pad for the cleanup from a previous execution of + // phase2. To continue unwindingly correctly, replace VRS[15] with the + // IP of the frame that the previous run of phase2 installed the context + // for. After this, continue unwinding as if normal. + // + // See #7.4.6 for details. + __unw_set_reg(cursor, UNW_REG_IP, + exception_object->unwinder_cache.reserved2); + resume = false; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE2_ERROR", + static_cast(exception_object)); + return _URC_FATAL_PHASE2_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " + "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + static_cast(exception_object), frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); + } +#endif + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); + // EHABI #7.2 + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(state, exception_object, context); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + static_cast(exception_object)); + // EHABI #7.2 + if (sp == exception_object->barrier_cache.sp) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now in phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", + static_cast(exception_object)); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + __unw_get_reg(cursor, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, + static_cast(exception_object), + pc, sp); + } + + { + // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume + // is called back, to find this same frame. + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + exception_object->unwinder_cache.reserved2 = (uint32_t)pc; + } + __unw_resume(cursor); + // __unw_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + + // # EHABI #7.4.3 + case _URC_FAILURE: + abort(); + + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + frame_count++; + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, + void *stop_parameter) { + // See comment at the start of unwind_phase1 regarding VRS integrity. + __unw_init_local(cursor, uc); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_force(ex_ojb=%p)", + static_cast(exception_object)); + // Walk each frame until we reach where search phase said to stop + while (true) { + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } +#endif + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (_Unwind_Context *)(cursor), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); + // EHABI #7.2 + exception_object->pr_cache.fnstart = frameInfo.start_ip; + exception_object->pr_cache.ehtp = + (_Unwind_EHT_Header *)frameInfo.unwind_info; + exception_object->pr_cache.additional = frameInfo.flags; + _Unwind_Reason_Code personalityResult = + (*p)(_US_FORCE_UNWIND | _US_UNWIND_FRAME_STARTING, exception_object, + context); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_resume(cursor); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + static_cast(exception_object)); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // This field for is for compatibility with GCC to say this isn't a forced + // unwind. EHABI #7.2 + exception_object->unwinder_cache.reserved1 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(&uc, &cursor, exception_object, false); +} + +_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { + // This is to be called when exception handling completes to give us a chance + // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. + (void)exception_object; +} + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", + static_cast(exception_object)); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + if (exception_object->unwinder_cache.reserved1) + unwind_phase2_forced( + &uc, &cursor, exception_object, + (_Unwind_Stop_Fn)exception_object->unwinder_cache.reserved1, + (void *)exception_object->unwinder_cache.reserved3); + else + unwind_phase2(&uc, &cursor, exception_object, true); + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx", + static_cast(context), (long long)result); + return result; +} + +static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, + void* valuep) { + uint64_t value = 0; + switch (representation) { + case _UVRSD_UINT32: + case _UVRSD_FLOAT: + memcpy(&value, valuep, sizeof(uint32_t)); + break; + + case _UVRSD_VFPX: + case _UVRSD_UINT64: + case _UVRSD_DOUBLE: + memcpy(&value, valuep, sizeof(uint64_t)); + break; + } + return value; +} + +_LIBUNWIND_EXPORT _Unwind_VRS_Result +_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX)", + static_cast(context), regclass, regno, + representation, + ValueAsBitPattern(representation, valuep)); + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + __unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), + *(unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +static _Unwind_VRS_Result +_Unwind_VRS_Get_Internal(_Unwind_Context *context, + _Unwind_VRS_RegClass regclass, uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + switch (regclass) { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 || regno > 15) + return _UVRSR_FAILED; + return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_VFP: + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + if (representation == _UVRSD_VFPX) { + // Can only touch d0-15 with FSTMFDX. + if (regno > 15) + return _UVRSR_FAILED; + __unw_save_vfp_as_X(cursor); + } else { + if (regno > 31) + return _UVRSR_FAILED; + } + return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), + (unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#if defined(__ARM_WMMX) + case _UVRSC_WMMXC: + if (representation != _UVRSD_UINT32 || regno > 3) + return _UVRSR_FAILED; + return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + case _UVRSC_WMMXD: + if (representation != _UVRSD_DOUBLE || regno > 31) + return _UVRSR_FAILED; + return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), + (unw_fpreg_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; +#else + case _UVRSC_WMMXC: + case _UVRSC_WMMXD: + break; +#endif + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +_LIBUNWIND_EXPORT _Unwind_VRS_Result +_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t regno, _Unwind_VRS_DataRepresentation representation, + void *valuep) { + _Unwind_VRS_Result result = + _Unwind_VRS_Get_Internal(context, regclass, regno, representation, + valuep); + _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " + "rep=%d, value=0x%llX, result = %d)", + static_cast(context), regclass, regno, + representation, + ValueAsBitPattern(representation, valuep), result); + return result; +} + +_Unwind_VRS_Result +_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, + uint32_t discriminator, + _Unwind_VRS_DataRepresentation representation) { + _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " + "discriminator=%d, representation=%d)", + static_cast(context), regclass, discriminator, + representation); + switch (regclass) { + case _UVRSC_WMMXC: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_CORE: { + if (representation != _UVRSD_UINT32) + return _UVRSR_FAILED; + // When popping SP from the stack, we don't want to override it from the + // computed new stack location. See EHABI #7.5.4 table 3. + bool poppedSP = false; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + for (uint32_t i = 0; i < 16; ++i) { + if (!(discriminator & static_cast(1 << i))) + continue; + uint32_t value = *sp++; + if (regclass == _UVRSC_CORE && i == 13) + poppedSP = true; + if (_Unwind_VRS_Set(context, regclass, i, + _UVRSD_UINT32, &value) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + } + if (!poppedSP) { + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp); + } + return _UVRSR_OK; + } + case _UVRSC_WMMXD: +#if !defined(__ARM_WMMX) + break; +#endif + case _UVRSC_VFP: { + if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + uint32_t first = discriminator >> 16; + uint32_t count = discriminator & 0xffff; + uint32_t end = first+count; + uint32_t* sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, + _UVRSD_UINT32, &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard + // format 1", which is equivalent to FSTMD + a padding word. + for (uint32_t i = first; i < end; ++i) { + // SP is only 32-bit aligned so don't copy 64-bit at a time. + uint64_t w0 = *sp++; + uint64_t w1 = *sp++; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint64_t value = (w1 << 32) | w0; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint64_t value = (w0 << 32) | w1; +#else +#error "Unable to determine endianess" +#endif + if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != + _UVRSR_OK) + return _UVRSR_FAILED; + } + if (representation == _UVRSD_VFPX) + ++sp; + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp); + } + } + _LIBUNWIND_ABORT("unsupported register class"); +} + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, + void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->unwinder_cache.reserved1 = (uintptr_t)stop; + exception_object->unwinder_cache.reserved3 = (uintptr_t)stop_parameter; + + return unwind_phase2_forced(&uc, &cursor, exception_object, stop, + stop_parameter); +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX", + static_cast(context), (long long)result); + return result; +} + + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + static_cast(exception_object)); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code +__gnu_unwind_frame(_Unwind_Exception *exception_object, + struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + if (__unw_step(cursor) != UNW_STEP_SUCCESS) + return _URC_FAILURE; + return _URC_OK; +} + +#endif // defined(_LIBUNWIND_ARM_EHABI) diff --git a/libunwind/src/Unwind-EHABI.h b/libunwind/src/Unwind-EHABI.h new file mode 100644 index 0000000000..6897082a33 --- /dev/null +++ b/libunwind/src/Unwind-EHABI.h @@ -0,0 +1,50 @@ +//===------------------------- Unwind-EHABI.hpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +#ifndef __UNWIND_EHABI_H__ +#define __UNWIND_EHABI_H__ + +#include <__libunwind_config.h> + +#if defined(_LIBUNWIND_ARM_EHABI) + +#include +#include + +// Unable to unwind in the ARM index table (section 5 EHABI). +#define UNW_EXIDX_CANTUNWIND 0x1 + +static inline uint32_t signExtendPrel31(uint32_t data) { + return data | ((data & 0x40000000u) << 1); +} + +static inline uint32_t readPrel31(const uint32_t *data) { + return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data)); +} + +#if defined(__cplusplus) +extern "C" { +#endif + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2( + _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // defined(_LIBUNWIND_ARM_EHABI) + +#endif // __UNWIND_EHABI_H__ diff --git a/libunwind/src/Unwind-seh.cpp b/libunwind/src/Unwind-seh.cpp new file mode 100644 index 0000000000..ad0b267659 --- /dev/null +++ b/libunwind/src/Unwind-seh.cpp @@ -0,0 +1,491 @@ +//===--------------------------- Unwind-seh.cpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements SEH-based Itanium C++ exceptions. +// +//===----------------------------------------------------------------------===// + +#include "config.h" + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "libunwind_ext.h" +#include "UnwindCursor.hpp" + +using namespace libunwind; + +#define STATUS_USER_DEFINED (1u << 29) + +#define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') + +#define MAKE_CUSTOM_STATUS(s, c) \ + ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) +#define MAKE_GCC_EXCEPTION(c) \ + MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) + +/// SEH exception raised by libunwind when the program calls +/// \c _Unwind_RaiseException. +#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 +/// SEH exception raised by libunwind to initiate phase 2 of exception +/// handling. +#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 + +static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); +static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); +static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, + DISPATCHER_CONTEXT *disp); + +/// Common implementation of SEH-style handler functions used by Itanium- +/// style frames. Depending on how and why it was called, it may do one of: +/// a) Delegate to the given Itanium-style personality function; or +/// b) Initiate a collided unwind to halt unwinding. +_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION +_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, + DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) { + unw_cursor_t cursor; + _Unwind_Exception *exc; + _Unwind_Action action; + struct _Unwind_Context *ctx = nullptr; + _Unwind_Reason_Code urc; + uintptr_t retval, target; + bool ours = false; + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)", + ms_exc->ExceptionCode, ms_exc->ExceptionFlags, + (void *)frame); + if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { + if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { + // Set up the upper return value (the lower one and the target PC + // were set in the call to RtlUnwindEx()) for the landing pad. +#ifdef __x86_64__ + disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; +#elif defined(__arm__) + disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; +#elif defined(__aarch64__) + disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; +#endif + } + // This is the collided unwind to the landing pad. Nothing to do. + return ExceptionContinueSearch; + } + + if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { + // This is (probably) a libunwind-controlled exception/unwind. Recover the + // parameters which we set below, and pass them to the personality function. + ours = true; + exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; + if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { + ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; + action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; + } + } else { + // Foreign exception. + // We can't interact with them (we don't know the original target frame + // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just + // pass without calling our destructors here. + return ExceptionContinueSearch; + } + if (!ctx) { + __unw_init_seh(&cursor, disp->ContextRecord); + __unw_seh_set_disp_ctx(&cursor, disp); + __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1); + ctx = (struct _Unwind_Context *)&cursor; + + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { + if (ours && ms_exc->NumberParameters > 1) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); + else + action = _UA_SEARCH_PHASE; + } else { + if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + else + action = _UA_CLEANUP_PHASE; + } + } + + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality " + "function %p(1, %d, %llx, %p, %p)", + (void *)pers, action, exc->exception_class, + (void *)exc, (void *)ctx); + urc = pers(1, action, exc->exception_class, exc, ctx); + _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); + switch (urc) { + case _URC_CONTINUE_UNWIND: + // If we're in phase 2, and the personality routine said to continue + // at the target frame, we're in real trouble. + if (action & _UA_HANDLER_FRAME) + _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); + return ExceptionContinueSearch; + case _URC_HANDLER_FOUND: + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, initiate phase 2 by unwinding. + if (ours && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 2. + if (IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); + exc->private_[1] = (ULONG_PTR)frame; + if (ours) { + ms_exc->NumberParameters = 4; + ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; + } + // FIXME: Indicate target frame in foreign case! + // phase 2: the clean up phase + RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + case _URC_INSTALL_CONTEXT: { + // If we were called by __libunwind_seh_personality(), indicate that + // a handler was found; otherwise, it's time to initiate a collided + // unwind to the target. + if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) + return 4 /* ExecptionExecuteHandler in mingw */; + // This should never happen in phase 1. + if (!IS_UNWINDING(ms_exc->ExceptionFlags)) + _LIBUNWIND_ABORT("Personality installed context during phase 1!"); +#ifdef __x86_64__ + exc->private_[2] = disp->TargetIp; + __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); + __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); +#elif defined(__arm__) + exc->private_[2] = disp->TargetPc; + __unw_get_reg(&cursor, UNW_ARM_R0, &retval); + __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); +#elif defined(__aarch64__) + exc->private_[2] = disp->TargetPc; + __unw_get_reg(&cursor, UNW_AARCH64_X0, &retval); + __unw_get_reg(&cursor, UNW_AARCH64_X1, &exc->private_[3]); +#endif + __unw_get_reg(&cursor, UNW_REG_IP, &target); + ms_exc->ExceptionCode = STATUS_GCC_UNWIND; +#ifdef __x86_64__ + ms_exc->ExceptionInformation[2] = disp->TargetIp; +#elif defined(__arm__) || defined(__aarch64__) + ms_exc->ExceptionInformation[2] = disp->TargetPc; +#endif + ms_exc->ExceptionInformation[3] = exc->private_[3]; + // Give NTRTL some scratch space to keep track of the collided unwind. + // Don't use the one that was passed in; we don't want to overwrite the + // context in the DISPATCHER_CONTEXT. + CONTEXT new_ctx; + RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); + _LIBUNWIND_ABORT("RtlUnwindEx() failed"); + } + // Anything else indicates a serious problem. + default: return ExceptionContinueExecution; + } +} + +/// Personality function returned by \c __unw_get_proc_info() in SEH contexts. +/// This is a wrapper that calls the real SEH handler function, which in +/// turn (at least, for Itanium-style frames) calls the real Itanium +/// personality function (see \c _GCC_specific_handler()). +extern "C" _Unwind_Reason_Code +__libunwind_seh_personality(int version, _Unwind_Action state, + uint64_t klass, _Unwind_Exception *exc, + struct _Unwind_Context *context) { + (void)version; + (void)klass; + EXCEPTION_RECORD ms_exc; + bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = 0; + ms_exc.NumberParameters = 3; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; + ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; + ms_exc.ExceptionInformation[2] = state; + DISPATCHER_CONTEXT *disp_ctx = + __unw_seh_get_disp_ctx((unw_cursor_t *)context); + EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, + (PVOID)disp_ctx->EstablisherFrame, + disp_ctx->ContextRecord, + disp_ctx); + switch (ms_act) { + case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; + case 4 /*ExceptionExecuteHandler*/: + return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; + default: + return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; + } +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + unw_cursor_t cursor2; + __unw_init_local(&cursor2, uc); + + // Walk each frame until we reach where search phase said to stop + while (__unw_step(&cursor2) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 + ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } +#endif + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_resume(&cursor2); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + +/// Called by \c __cxa_throw(). Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + (void *)exception_object); + + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + memset(exception_object->private_, 0, sizeof(exception_object->private_)); + + // phase 1: the search phase + // We'll let the system do that for us. + RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); + + // If we get here, either something went horribly wrong or we reached the + // top of the stack. Either way, let libc++abi call std::terminate(). + return _URC_END_OF_STACK; +} + +/// When \c _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function; the landing +/// pad code may then call \c _Unwind_Resume() to continue with the +/// unwinding. Note: the call to \c _Unwind_Resume() is from compiler +/// geneated user code. All other \c _Unwind_* routines are called +/// by the C++ runtime \c __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call \c __cxa_rethrow() which +/// in turn calls \c _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); + + if (exception_object->private_[0] != 0) { + unw_context_t uc; + + __unw_getcontext(&uc); + unwind_phase2_forced(&uc, exception_object, + (_Unwind_Stop_Fn) exception_object->private_[0], + (void *)exception_object->private_[4]); + } else { + // Recover the parameters for the unwind from the exception object + // so we can start unwinding again. + EXCEPTION_RECORD ms_exc; + CONTEXT ms_ctx; + UNWIND_HISTORY_TABLE hist; + + memset(&ms_exc, 0, sizeof(ms_exc)); + memset(&hist, 0, sizeof(hist)); + ms_exc.ExceptionCode = STATUS_GCC_THROW; + ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ms_exc.NumberParameters = 4; + ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; + ms_exc.ExceptionInformation[1] = exception_object->private_[1]; + ms_exc.ExceptionInformation[2] = exception_object->private_[2]; + ms_exc.ExceptionInformation[3] = exception_object->private_[3]; + RtlUnwindEx((PVOID)exception_object->private_[1], + (PVOID)exception_object->private_[2], &ms_exc, + exception_object, &ms_ctx, &hist); + } + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement \c longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + __unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_[0] = (uintptr_t) stop; + exception_object->private_[4] = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); +} + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + uintptr_t result = + (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context); + uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { +#ifdef _LIBUNWIND_TARGET_X86_64 + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_ARM) + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); + auto *co = reinterpret_cast(cursor); + co->setInfoBasedOnIPRegister(); + return UNW_ESUCCESS; +#else + return UNW_EINVAL; +#endif +} + +static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) { +#ifdef _LIBUNWIND_TARGET_X86_64 + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_ARM) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return reinterpret_cast *>(cursor)->getDispatcherContext(); +#else + return nullptr; +#endif +} + +static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, + DISPATCHER_CONTEXT *disp) { +#ifdef _LIBUNWIND_TARGET_X86_64 + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_ARM) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + reinterpret_cast *>(cursor)->setDispatcherContext(disp); +#endif +} + +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c new file mode 100644 index 0000000000..fd2a95b74c --- /dev/null +++ b/libunwind/src/Unwind-sjlj.c @@ -0,0 +1,528 @@ +//===--------------------------- Unwind-sjlj.c ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements setjump-longjump based C++ exceptions +// +//===----------------------------------------------------------------------===// + +#include + +#include +#include +#include +#include + +#include "config.h" + +/// With SJLJ based exceptions, any function that has a catch clause or needs to +/// do any clean up when an exception propagates through it, needs to call +/// \c _Unwind_SjLj_Register at the start of the function and +/// \c _Unwind_SjLj_Unregister at the end. The register function is called with +/// the address of a block of memory in the function's stack frame. The runtime +/// keeps a linked list (stack) of these blocks - one per thread. The calling +/// function also sets the personality and lsda fields of the block. + +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) + +struct _Unwind_FunctionContext { + // next function in stack of handlers + struct _Unwind_FunctionContext *prev; + +#if defined(__ve__) + // VE requires to store 64 bit pointers in the buffer for SjLj execption. + // We expand the size of values defined here. This size must be matched + // to the size returned by TargetMachine::getSjLjDataSize(). + + // set by calling function before registering to be the landing pad + uint64_t resumeLocation; + + // set by personality handler to be parameters passed to landing pad function + uint64_t resumeParameters[4]; +#else + // set by calling function before registering to be the landing pad + uint32_t resumeLocation; + + // set by personality handler to be parameters passed to landing pad function + uint32_t resumeParameters[4]; +#endif + + // set by calling function before registering + _Unwind_Personality_Fn personality; // arm offset=24 + uintptr_t lsda; // arm offset=28 + + // variable length array, contains registers to restore + // 0 = r7, 1 = pc, 2 = sp + void *jbuf[]; +}; + +#if defined(_LIBUNWIND_HAS_NO_THREADS) +# define _LIBUNWIND_THREAD_LOCAL +#else +# if __STDC_VERSION__ >= 201112L +# define _LIBUNWIND_THREAD_LOCAL _Thread_local +# elif defined(_MSC_VER) +# define _LIBUNWIND_THREAD_LOCAL __declspec(thread) +# elif defined(__GNUC__) || defined(__clang__) +# define _LIBUNWIND_THREAD_LOCAL __thread +# else +# error Unable to create thread local storage +# endif +#endif + + +#if !defined(FOR_DYLD) + +#if defined(__APPLE__) +#include +#else +static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; +#endif + +static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { +#if defined(__APPLE__) + return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); +#else + return stack; +#endif +} + +static void +__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { +#if defined(__APPLE__) + _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); +#else + stack = fc; +#endif +} + +#endif + + +/// Called at start of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) { + fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); + __Unwind_SjLj_SetTopOfFunctionStack(fc); +} + + +/// Called at end of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { + __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); +} + + +static _Unwind_Reason_Code +unwind_phase1(struct _Unwind_Exception *exception_object) { + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", + (void *)c); + + // walk each frame looking for a place to stop + for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { + + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c); + // if there is a personality routine, ask it if it will want to stop at this + // frame + if (c->personality != NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " + "personality function %p", + (void *)exception_object, + (void *)c->personality); + _Unwind_Reason_Code personalityResult = (*c->personality)( + 1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember function context + handlerNotFound = false; + exception_object->private_2 = (uintptr_t) c; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_HANDLER_FOUND", + (void *)exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + + +static _Unwind_Reason_Code +unwind_phase2(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + (void *)exception_object); + + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p", + (void *)exception_object, (void *)c); + + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + _Unwind_Action action = _UA_CLEANUP_PHASE; + if ((uintptr_t) c == exception_object->private_2) + action = (_Unwind_Action)( + _UA_CLEANUP_PHASE | + _UA_HANDLER_FRAME); // tell personality this was the frame it marked + // in phase 1 + _Unwind_Reason_Code personalityResult = + (*c->personality)(1, action, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + if ((uintptr_t) c == exception_object->private_2) { + // phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now if phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " + "_URC_INSTALL_CONTEXT, will resume at " + "landing pad %p", + (void *)exception_object, c->jbuf[1]); + // personality routine says to transfer control to landing pad + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + // __unw_resume() only returns if there was an error + return _URC_FATAL_PHASE2_ERROR; + default: + // something went wrong + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; +} + + +static _Unwind_Reason_Code +unwind_phase2_forced(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { + + // get next frame (skip over first which is _Unwind_RaiseException) + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } + + // call stop function at each frame + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "calling personality function %p", + (void *)exception_object, (void *)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_CONTINUE_UNWIND", + (void *)exception_object); + // destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_INSTALL_CONTEXT", + (void *)exception_object); + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + break; + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // call stop function one last time and tell it we've reached the end of the + // stack + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; +} + + +/// Called by __cxa_throw. Only returns if there is a fatal error +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", + (void *)exception_object); + + // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right + // thing + exception_object->private_1 = 0; + exception_object->private_2 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(exception_object); +} + + + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Re-throwing an exception is implemented by having the code call +/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", + (void *)exception_object); + + if (exception_object->private_1 != 0) + unwind_phase2_forced(exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(exception_object); + + // clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); +} + + +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " + "private_1=%" PRIuPTR, + (void *)exception_object, exception_object->private_1); + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception. + if (exception_object->private_1 == 0) { + return _Unwind_SjLj_RaiseException(exception_object); + // should return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate() + } + + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_SjLj_Resume(exception_object); + _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " + "_Unwind_SjLj_Resume() which unexpectedly returned"); +} + + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " + "=> 0x%" PRIuPTR, + (void *)context, ufc->lsda); + return ufc->lsda; +} + + +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, + int index) { + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context, + index); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + return ufc->resumeParameters[index]; +} + + +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR + ")", + (void *)context, index, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeParameters[index] = new_value; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32, + (void *)context, ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + *ipBefore = 0; + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32, + (void *)context, (void *)ipBefore, + ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to alter instruction pointer. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")", + (void *)context, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeLocation = new_value - 1; +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context); + return 0; +} + + +/// Called by personality handler during phase 2 if a foreign exception +/// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + (void *)exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + + + +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); +} + + +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); +} + + +/// Called by personality handler to get "Call Frame Area" for current frame. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context); + if (context != NULL) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + // Setjmp/longjmp based exceptions don't have a true CFA. + // Instead, the SP in the jmpbuf is the closest approximation. + return (uintptr_t) ufc->jbuf[2]; + } + return 0; +} + +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp new file mode 100644 index 0000000000..7157fa92bf --- /dev/null +++ b/libunwind/src/UnwindCursor.hpp @@ -0,0 +1,2146 @@ +//===------------------------- UnwindCursor.hpp ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// C++ interface to lower levels of libunwind +//===----------------------------------------------------------------------===// + +#ifndef __UNWINDCURSOR_HPP__ +#define __UNWINDCURSOR_HPP__ + +#include "cet_unwind.h" +#include +#include +#include +#include + +#ifdef _WIN32 + #include + #include +#endif +#ifdef __APPLE__ + #include +#endif + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and +// earlier) SDKs. +// MinGW-w64 has always provided this struct. + #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \ + !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000 +struct _DISPATCHER_CONTEXT { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + PEXCEPTION_ROUTINE LanguageHandler; + PVOID HandlerData; + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; +}; + #endif + +struct UNWIND_INFO { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + uint16_t UnwindCodes[2]; +}; + +extern "C" _Unwind_Reason_Code __libunwind_seh_personality( + int, _Unwind_Action, uint64_t, _Unwind_Exception *, + struct _Unwind_Context *); + +#endif + +#include "config.h" + +#include "AddressSpace.hpp" +#include "CompactUnwinder.hpp" +#include "config.h" +#include "DwarfInstructions.hpp" +#include "EHHeaderParser.hpp" +#include "libunwind.h" +#include "Registers.hpp" +#include "RWMutex.hpp" +#include "Unwind-EHABI.h" + +namespace libunwind { + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +/// Cache of recently found FDEs. +template +class _LIBUNWIND_HIDDEN DwarfFDECache { + typedef typename A::pint_t pint_t; +public: + static constexpr pint_t kSearchAll = static_cast(-1); + static pint_t findFDE(pint_t mh, pint_t pc); + static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); + static void removeAllIn(pint_t mh); + static void iterateCacheEntries(void (*func)(unw_word_t ip_start, + unw_word_t ip_end, + unw_word_t fde, unw_word_t mh)); + +private: + + struct entry { + pint_t mh; + pint_t ip_start; + pint_t ip_end; + pint_t fde; + }; + + // These fields are all static to avoid needing an initializer. + // There is only one instance of this class per process. + static RWMutex _lock; +#ifdef __APPLE__ + static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); + static bool _registeredForDyldUnloads; +#endif + static entry *_buffer; + static entry *_bufferUsed; + static entry *_bufferEnd; + static entry _initialBuffer[64]; +}; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_buffer = _initialBuffer; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_bufferUsed = _initialBuffer; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_bufferEnd = &_initialBuffer[64]; + +template +typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; + +template +RWMutex DwarfFDECache::_lock; + +#ifdef __APPLE__ +template +bool DwarfFDECache::_registeredForDyldUnloads = false; +#endif + +template +typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { + pint_t result = 0; + _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared()); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + if ((mh == p->mh) || (mh == kSearchAll)) { + if ((p->ip_start <= pc) && (pc < p->ip_end)) { + result = p->fde; + break; + } + } + } + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared()); + return result; +} + +template +void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, + pint_t fde) { +#if !defined(_LIBUNWIND_NO_HEAP) + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + if (_bufferUsed >= _bufferEnd) { + size_t oldSize = (size_t)(_bufferEnd - _buffer); + size_t newSize = oldSize * 4; + // Can't use operator new (we are below it). + entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); + memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); + if (_buffer != _initialBuffer) + free(_buffer); + _buffer = newBuffer; + _bufferUsed = &newBuffer[oldSize]; + _bufferEnd = &newBuffer[newSize]; + } + _bufferUsed->mh = mh; + _bufferUsed->ip_start = ip_start; + _bufferUsed->ip_end = ip_end; + _bufferUsed->fde = fde; + ++_bufferUsed; +#ifdef __APPLE__ + if (!_registeredForDyldUnloads) { + _dyld_register_func_for_remove_image(&dyldUnloadHook); + _registeredForDyldUnloads = true; + } +#endif + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +#endif +} + +template +void DwarfFDECache::removeAllIn(pint_t mh) { + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + entry *d = _buffer; + for (const entry *s = _buffer; s < _bufferUsed; ++s) { + if (s->mh != mh) { + if (d != s) + *d = *s; + ++d; + } + } + _bufferUsed = d; + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +} + +#ifdef __APPLE__ +template +void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { + removeAllIn((pint_t) mh); +} +#endif + +template +void DwarfFDECache::iterateCacheEntries(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_LOG_IF_FALSE(_lock.lock()); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + (*func)(p->ip_start, p->ip_end, p->fde, p->mh); + } + _LIBUNWIND_LOG_IF_FALSE(_lock.unlock()); +} +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + + +#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) + +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) +template class UnwindSectionHeader { +public: + UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t version() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, version)); + } + uint32_t commonEncodingsArraySectionOffset() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, + commonEncodingsArraySectionOffset)); + } + uint32_t commonEncodingsArrayCount() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + commonEncodingsArrayCount)); + } + uint32_t personalityArraySectionOffset() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + personalityArraySectionOffset)); + } + uint32_t personalityArrayCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, personalityArrayCount)); + } + uint32_t indexSectionOffset() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexSectionOffset)); + } + uint32_t indexCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionIndexArray { +public: + UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + functionOffset)); + } + uint32_t secondLevelPagesSectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + secondLevelPagesSectionOffset)); + } + uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + lsdaIndexArraySectionOffset)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionRegularPageHeader { +public: + UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_regular_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_regular_second_level_page_header, entryCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionRegularArray { +public: + UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, + functionOffset)); + } + uint32_t encoding(uint32_t index) const { + return _addressSpace.get32( + _addr + + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionCompressedPageHeader { +public: + UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); + } + uint16_t encodingsPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsPageOffset)); + } + uint16_t encodingsCount() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionCompressedArray { +public: + UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } + uint16_t encodingIndex(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionLsdaArray { +public: + UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, functionOffset)); + } + uint32_t lsdaOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, lsdaOffset)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +class _LIBUNWIND_HIDDEN AbstractUnwindCursor { +public: + // NOTE: provide a class specific placement deallocation function (S5.3.4 p20) + // This avoids an unnecessary dependency to libc++abi. + void operator delete(void *, size_t) {} + + virtual ~AbstractUnwindCursor() {} + virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); } + virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); } + virtual void setReg(int, unw_word_t) { + _LIBUNWIND_ABORT("setReg not implemented"); + } + virtual bool validFloatReg(int) { + _LIBUNWIND_ABORT("validFloatReg not implemented"); + } + virtual unw_fpreg_t getFloatReg(int) { + _LIBUNWIND_ABORT("getFloatReg not implemented"); + } + virtual void setFloatReg(int, unw_fpreg_t) { + _LIBUNWIND_ABORT("setFloatReg not implemented"); + } + virtual int step() { _LIBUNWIND_ABORT("step not implemented"); } + virtual void getInfo(unw_proc_info_t *) { + _LIBUNWIND_ABORT("getInfo not implemented"); + } + virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); } + virtual bool isSignalFrame() { + _LIBUNWIND_ABORT("isSignalFrame not implemented"); + } + virtual bool getFunctionName(char *, size_t, unw_word_t *) { + _LIBUNWIND_ABORT("getFunctionName not implemented"); + } + virtual void setInfoBasedOnIPRegister(bool = false) { + _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented"); + } + virtual const char *getRegisterName(int) { + _LIBUNWIND_ABORT("getRegisterName not implemented"); + } +#ifdef __arm__ + virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); } +#endif + +#if defined(_LIBUNWIND_USE_CET) + virtual void *get_registers() { + _LIBUNWIND_ABORT("get_registers not implemented"); + } +#endif +}; + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32) + +/// \c UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack-allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor { + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(CONTEXT *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual unw_fpreg_t getFloatReg(int); + virtual void setFloatReg(int, unw_fpreg_t); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); +#ifdef __arm__ + virtual void saveVFPAsX(); +#endif + + DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; } + void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; } + + // libunwind does not and should not depend on C++ library which means that we + // need our own defition of inline placement new. + static void *operator new(size_t, UnwindCursor *p) { return p; } + +private: + + pint_t getLastPC() const { return _dispContext.ControlPc; } + void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc, + &_dispContext.ImageBase, + _dispContext.HistoryTable); + *base = _dispContext.ImageBase; + return _dispContext.FunctionEntry; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { + _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER, + _dispContext.ImageBase, + _dispContext.ControlPc, + _dispContext.FunctionEntry, + _dispContext.ContextRecord, + &_dispContext.HandlerData, + &_dispContext.EstablisherFrame, + NULL); + // Update some fields of the unwind info now, since we have them. + _info.lsda = reinterpret_cast(_dispContext.HandlerData); + if (_dispContext.LanguageHandler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + return UNW_STEP_SUCCESS; + } + + A &_addressSpace; + unw_proc_info_t _info; + DISPATCHER_CONTEXT _dispContext; + CONTEXT _msContext; + UNWIND_HISTORY_TABLE _histTable; + bool _unwindInfoMissing; +}; + + +template +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + // Initialize MS context from ours. + R r(context); + _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT; +#if defined(_LIBUNWIND_TARGET_X86_64) + _msContext.Rax = r.getRegister(UNW_X86_64_RAX); + _msContext.Rcx = r.getRegister(UNW_X86_64_RCX); + _msContext.Rdx = r.getRegister(UNW_X86_64_RDX); + _msContext.Rbx = r.getRegister(UNW_X86_64_RBX); + _msContext.Rsp = r.getRegister(UNW_X86_64_RSP); + _msContext.Rbp = r.getRegister(UNW_X86_64_RBP); + _msContext.Rsi = r.getRegister(UNW_X86_64_RSI); + _msContext.Rdi = r.getRegister(UNW_X86_64_RDI); + _msContext.R8 = r.getRegister(UNW_X86_64_R8); + _msContext.R9 = r.getRegister(UNW_X86_64_R9); + _msContext.R10 = r.getRegister(UNW_X86_64_R10); + _msContext.R11 = r.getRegister(UNW_X86_64_R11); + _msContext.R12 = r.getRegister(UNW_X86_64_R12); + _msContext.R13 = r.getRegister(UNW_X86_64_R13); + _msContext.R14 = r.getRegister(UNW_X86_64_R14); + _msContext.R15 = r.getRegister(UNW_X86_64_R15); + _msContext.Rip = r.getRegister(UNW_REG_IP); + union { + v128 v; + M128A m; + } t; + t.v = r.getVectorRegister(UNW_X86_64_XMM0); + _msContext.Xmm0 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM1); + _msContext.Xmm1 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM2); + _msContext.Xmm2 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM3); + _msContext.Xmm3 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM4); + _msContext.Xmm4 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM5); + _msContext.Xmm5 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM6); + _msContext.Xmm6 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM7); + _msContext.Xmm7 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM8); + _msContext.Xmm8 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM9); + _msContext.Xmm9 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM10); + _msContext.Xmm10 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM11); + _msContext.Xmm11 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM12); + _msContext.Xmm12 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM13); + _msContext.Xmm13 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM14); + _msContext.Xmm14 = t.m; + t.v = r.getVectorRegister(UNW_X86_64_XMM15); + _msContext.Xmm15 = t.m; +#elif defined(_LIBUNWIND_TARGET_ARM) + _msContext.R0 = r.getRegister(UNW_ARM_R0); + _msContext.R1 = r.getRegister(UNW_ARM_R1); + _msContext.R2 = r.getRegister(UNW_ARM_R2); + _msContext.R3 = r.getRegister(UNW_ARM_R3); + _msContext.R4 = r.getRegister(UNW_ARM_R4); + _msContext.R5 = r.getRegister(UNW_ARM_R5); + _msContext.R6 = r.getRegister(UNW_ARM_R6); + _msContext.R7 = r.getRegister(UNW_ARM_R7); + _msContext.R8 = r.getRegister(UNW_ARM_R8); + _msContext.R9 = r.getRegister(UNW_ARM_R9); + _msContext.R10 = r.getRegister(UNW_ARM_R10); + _msContext.R11 = r.getRegister(UNW_ARM_R11); + _msContext.R12 = r.getRegister(UNW_ARM_R12); + _msContext.Sp = r.getRegister(UNW_ARM_SP); + _msContext.Lr = r.getRegister(UNW_ARM_LR); + _msContext.Pc = r.getRegister(UNW_ARM_IP); + for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) { + union { + uint64_t w; + double d; + } d; + d.d = r.getFloatRegister(i); + _msContext.D[i - UNW_ARM_D0] = d.w; + } +#elif defined(_LIBUNWIND_TARGET_AARCH64) + for (int i = UNW_AARCH64_X0; i <= UNW_ARM64_X30; ++i) + _msContext.X[i - UNW_AARCH64_X0] = r.getRegister(i); + _msContext.Sp = r.getRegister(UNW_REG_SP); + _msContext.Pc = r.getRegister(UNW_REG_IP); + for (int i = UNW_AARCH64_V0; i <= UNW_ARM64_D31; ++i) + _msContext.V[i - UNW_AARCH64_V0].D[0] = r.getFloatRegister(i); +#endif +} + +template +UnwindCursor::UnwindCursor(CONTEXT *context, A &as) + : _addressSpace(as), _unwindInfoMissing(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); + memset(&_histTable, 0, sizeof(_histTable)); + _dispContext.ContextRecord = &_msContext; + _dispContext.HistoryTable = &_histTable; + _msContext = *context; +} + + +template +bool UnwindCursor::validReg(int regNum) { + if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true; +#if defined(_LIBUNWIND_TARGET_X86_64) + if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true; +#elif defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_AARCH64_X0 && regNum <= UNW_ARM64_X30) return true; +#endif + return false; +} + +template +unw_word_t UnwindCursor::getReg(int regNum) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: return _msContext.Rip; + case UNW_X86_64_RAX: return _msContext.Rax; + case UNW_X86_64_RDX: return _msContext.Rdx; + case UNW_X86_64_RCX: return _msContext.Rcx; + case UNW_X86_64_RBX: return _msContext.Rbx; + case UNW_REG_SP: + case UNW_X86_64_RSP: return _msContext.Rsp; + case UNW_X86_64_RBP: return _msContext.Rbp; + case UNW_X86_64_RSI: return _msContext.Rsi; + case UNW_X86_64_RDI: return _msContext.Rdi; + case UNW_X86_64_R8: return _msContext.R8; + case UNW_X86_64_R9: return _msContext.R9; + case UNW_X86_64_R10: return _msContext.R10; + case UNW_X86_64_R11: return _msContext.R11; + case UNW_X86_64_R12: return _msContext.R12; + case UNW_X86_64_R13: return _msContext.R13; + case UNW_X86_64_R14: return _msContext.R14; + case UNW_X86_64_R15: return _msContext.R15; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: return _msContext.R0; + case UNW_ARM_R1: return _msContext.R1; + case UNW_ARM_R2: return _msContext.R2; + case UNW_ARM_R3: return _msContext.R3; + case UNW_ARM_R4: return _msContext.R4; + case UNW_ARM_R5: return _msContext.R5; + case UNW_ARM_R6: return _msContext.R6; + case UNW_ARM_R7: return _msContext.R7; + case UNW_ARM_R8: return _msContext.R8; + case UNW_ARM_R9: return _msContext.R9; + case UNW_ARM_R10: return _msContext.R10; + case UNW_ARM_R11: return _msContext.R11; + case UNW_ARM_R12: return _msContext.R12; + case UNW_REG_SP: + case UNW_ARM_SP: return _msContext.Sp; + case UNW_ARM_LR: return _msContext.Lr; + case UNW_REG_IP: + case UNW_ARM_IP: return _msContext.Pc; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: return _msContext.Sp; + case UNW_REG_IP: return _msContext.Pc; + default: return _msContext.X[regNum - UNW_AARCH64_X0]; +#endif + } + _LIBUNWIND_ABORT("unsupported register"); +} + +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + switch (regNum) { +#if defined(_LIBUNWIND_TARGET_X86_64) + case UNW_REG_IP: _msContext.Rip = value; break; + case UNW_X86_64_RAX: _msContext.Rax = value; break; + case UNW_X86_64_RDX: _msContext.Rdx = value; break; + case UNW_X86_64_RCX: _msContext.Rcx = value; break; + case UNW_X86_64_RBX: _msContext.Rbx = value; break; + case UNW_REG_SP: + case UNW_X86_64_RSP: _msContext.Rsp = value; break; + case UNW_X86_64_RBP: _msContext.Rbp = value; break; + case UNW_X86_64_RSI: _msContext.Rsi = value; break; + case UNW_X86_64_RDI: _msContext.Rdi = value; break; + case UNW_X86_64_R8: _msContext.R8 = value; break; + case UNW_X86_64_R9: _msContext.R9 = value; break; + case UNW_X86_64_R10: _msContext.R10 = value; break; + case UNW_X86_64_R11: _msContext.R11 = value; break; + case UNW_X86_64_R12: _msContext.R12 = value; break; + case UNW_X86_64_R13: _msContext.R13 = value; break; + case UNW_X86_64_R14: _msContext.R14 = value; break; + case UNW_X86_64_R15: _msContext.R15 = value; break; +#elif defined(_LIBUNWIND_TARGET_ARM) + case UNW_ARM_R0: _msContext.R0 = value; break; + case UNW_ARM_R1: _msContext.R1 = value; break; + case UNW_ARM_R2: _msContext.R2 = value; break; + case UNW_ARM_R3: _msContext.R3 = value; break; + case UNW_ARM_R4: _msContext.R4 = value; break; + case UNW_ARM_R5: _msContext.R5 = value; break; + case UNW_ARM_R6: _msContext.R6 = value; break; + case UNW_ARM_R7: _msContext.R7 = value; break; + case UNW_ARM_R8: _msContext.R8 = value; break; + case UNW_ARM_R9: _msContext.R9 = value; break; + case UNW_ARM_R10: _msContext.R10 = value; break; + case UNW_ARM_R11: _msContext.R11 = value; break; + case UNW_ARM_R12: _msContext.R12 = value; break; + case UNW_REG_SP: + case UNW_ARM_SP: _msContext.Sp = value; break; + case UNW_ARM_LR: _msContext.Lr = value; break; + case UNW_REG_IP: + case UNW_ARM_IP: _msContext.Pc = value; break; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + case UNW_REG_SP: _msContext.Sp = value; break; + case UNW_REG_IP: _msContext.Pc = value; break; + case UNW_AARCH64_X0: + case UNW_AARCH64_X1: + case UNW_AARCH64_X2: + case UNW_AARCH64_X3: + case UNW_AARCH64_X4: + case UNW_AARCH64_X5: + case UNW_AARCH64_X6: + case UNW_AARCH64_X7: + case UNW_AARCH64_X8: + case UNW_AARCH64_X9: + case UNW_AARCH64_X10: + case UNW_AARCH64_X11: + case UNW_AARCH64_X12: + case UNW_AARCH64_X13: + case UNW_AARCH64_X14: + case UNW_AARCH64_X15: + case UNW_AARCH64_X16: + case UNW_AARCH64_X17: + case UNW_AARCH64_X18: + case UNW_AARCH64_X19: + case UNW_AARCH64_X20: + case UNW_AARCH64_X21: + case UNW_AARCH64_X22: + case UNW_AARCH64_X23: + case UNW_AARCH64_X24: + case UNW_AARCH64_X25: + case UNW_AARCH64_X26: + case UNW_AARCH64_X27: + case UNW_AARCH64_X28: + case UNW_AARCH64_FP: + case UNW_AARCH64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break; +#endif + default: + _LIBUNWIND_ABORT("unsupported register"); + } +} + +template +bool UnwindCursor::validFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true; + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true; +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (regNum >= UNW_AARCH64_V0 && regNum <= UNW_ARM64_D31) return true; +#else + (void)regNum; +#endif + return false; +} + +template +unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.w = _msContext.S[regNum - UNW_ARM_S0]; + return d.f; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.w = _msContext.D[regNum - UNW_ARM_D0]; + return d.d; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + return _msContext.V[regNum - UNW_AARCH64_V0].D[0]; +#else + (void)regNum; + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template +void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { +#if defined(_LIBUNWIND_TARGET_ARM) + if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) { + union { + uint32_t w; + float f; + } d; + d.f = value; + _msContext.S[regNum - UNW_ARM_S0] = d.w; + } + if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) { + union { + uint64_t w; + double d; + } d; + d.d = value; + _msContext.D[regNum - UNW_ARM_D0] = d.w; + } + _LIBUNWIND_ABORT("unsupported float register"); +#elif defined(_LIBUNWIND_TARGET_AARCH64) + _msContext.V[regNum - UNW_AARCH64_V0].D[0] = value; +#else + (void)regNum; + (void)value; + _LIBUNWIND_ABORT("float registers unimplemented"); +#endif +} + +template void UnwindCursor::jumpto() { + RtlRestoreContext(&_msContext, nullptr); +} + +#ifdef __arm__ +template void UnwindCursor::saveVFPAsX() {} +#endif + +template +const char *UnwindCursor::getRegisterName(int regNum) { + return R::getRegisterName(regNum); +} + +template bool UnwindCursor::isSignalFrame() { + return false; +} + +#else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32) + +/// UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor{ + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual unw_fpreg_t getFloatReg(int); + virtual void setFloatReg(int, unw_fpreg_t); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); +#ifdef __arm__ + virtual void saveVFPAsX(); +#endif + +#if defined(_LIBUNWIND_USE_CET) + virtual void *get_registers() { return &_registers; } +#endif + // libunwind does not and should not depend on C++ library which means that we + // need our own defition of inline placement new. + static void *operator new(size_t, UnwindCursor *p) { return p; } + +private: + +#if defined(_LIBUNWIND_ARM_EHABI) + bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s); + + int stepWithEHABI() { + size_t len = 0; + size_t off = 0; + // FIXME: Calling decode_eht_entry() here is violating the libunwind + // abstraction layer. + const uint32_t *ehtp = + decode_eht_entry(reinterpret_cast(_info.unwind_info), + &off, &len); + if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) != + _URC_CONTINUE_UNWIND) + return UNW_STEP_END; + return UNW_STEP_SUCCESS; + } +#endif + +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + bool setInfoForSigReturn() { + R dummy; + return setInfoForSigReturn(dummy); + } + int stepThroughSigReturn() { + R dummy; + return stepThroughSigReturn(dummy); + } + bool setInfoForSigReturn(Registers_arm64 &); + int stepThroughSigReturn(Registers_arm64 &); + template bool setInfoForSigReturn(Registers &) { + return false; + } + template int stepThroughSigReturn(Registers &) { + return UNW_STEP_END; + } +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + bool getInfoFromFdeCie(const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, + pint_t pc, uintptr_t dso_base); + bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint=0); + int stepWithDwarfFDE() { + return DwarfInstructions::stepWithDwarf(_addressSpace, + (pint_t)this->getReg(UNW_REG_IP), + (pint_t)_info.unwind_info, + _registers, _isSignalFrame); + } +#endif + +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + bool getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s); + int stepWithCompactEncoding() { + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + if ( compactSaysUseDwarf() ) + return stepWithDwarfFDE(); + #endif + R dummy; + return stepWithCompactEncoding(dummy); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + int stepWithCompactEncoding(Registers_x86_64 &) { + return CompactUnwinder_x86_64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + int stepWithCompactEncoding(Registers_x86 &) { + return CompactUnwinder_x86::stepWithCompactEncoding( + _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + int stepWithCompactEncoding(Registers_ppc &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + int stepWithCompactEncoding(Registers_ppc64 &) { + return UNW_EINVAL; + } +#endif + + +#if defined(_LIBUNWIND_TARGET_AARCH64) + int stepWithCompactEncoding(Registers_arm64 &) { + return CompactUnwinder_arm64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + int stepWithCompactEncoding(Registers_mips_o32 &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + int stepWithCompactEncoding(Registers_mips_newabi &) { + return UNW_EINVAL; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + int stepWithCompactEncoding(Registers_riscv &) { + return UNW_EINVAL; + } +#endif + + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { + R dummy; + return compactSaysUseDwarf(dummy, offset); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_AARCH64) + bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_O32) + bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI) + bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const { + return true; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const { + return true; + } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + compact_unwind_encoding_t dwarfEncoding() const { + R dummy; + return dwarfEncoding(dummy); + } + +#if defined(_LIBUNWIND_TARGET_X86_64) + compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { + return UNWIND_X86_64_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_I386) + compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { + return UNWIND_X86_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC) + compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_PPC64) + compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_AARCH64) + compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { + return UNWIND_ARM64_MODE_DWARF; + } +#endif + +#if defined(_LIBUNWIND_TARGET_ARM) + compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_OR1K) + compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_HEXAGON) + compact_unwind_encoding_t dwarfEncoding(Registers_hexagon &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_O32) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const { + return 0; + } +#endif + +#if defined (_LIBUNWIND_TARGET_MIPS_NEWABI) + compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const { + return 0; + } +#endif + +#if defined(_LIBUNWIND_TARGET_SPARC) + compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; } +#endif + +#if defined (_LIBUNWIND_TARGET_RISCV) + compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const { + return 0; + } +#endif + +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // For runtime environments using SEH unwind data without Windows runtime + // support. + pint_t getLastPC() const { /* FIXME: Implement */ return 0; } + void setLastPC(pint_t pc) { /* FIXME: Implement */ } + RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) { + /* FIXME: Implement */ + *base = 0; + return nullptr; + } + bool getInfoFromSEH(pint_t pc); + int stepWithSEHData() { /* FIXME: Implement */ return 0; } +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + + + A &_addressSpace; + R _registers; + unw_proc_info_t _info; + bool _unwindInfoMissing; + bool _isSignalFrame; +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + bool _isSigReturn = false; +#endif +}; + + +template +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _registers(context), _unwindInfoMissing(false), + _isSignalFrame(false) { + static_assert((check_fit, unw_cursor_t>::does_fit), + "UnwindCursor<> does not fit in unw_cursor_t"); + static_assert((alignof(UnwindCursor) <= alignof(unw_cursor_t)), + "UnwindCursor<> requires more alignment than unw_cursor_t"); + memset(&_info, 0, sizeof(_info)); +} + +template +UnwindCursor::UnwindCursor(A &as, void *) + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + memset(&_info, 0, sizeof(_info)); + // FIXME + // fill in _registers from thread arg +} + + +template +bool UnwindCursor::validReg(int regNum) { + return _registers.validRegister(regNum); +} + +template +unw_word_t UnwindCursor::getReg(int regNum) { + return _registers.getRegister(regNum); +} + +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + _registers.setRegister(regNum, (typename A::pint_t)value); +} + +template +bool UnwindCursor::validFloatReg(int regNum) { + return _registers.validFloatRegister(regNum); +} + +template +unw_fpreg_t UnwindCursor::getFloatReg(int regNum) { + return _registers.getFloatRegister(regNum); +} + +template +void UnwindCursor::setFloatReg(int regNum, unw_fpreg_t value) { + _registers.setFloatRegister(regNum, value); +} + +template void UnwindCursor::jumpto() { + _registers.jumpto(); +} + +#ifdef __arm__ +template void UnwindCursor::saveVFPAsX() { + _registers.saveVFPAsX(); +} +#endif + +template +const char *UnwindCursor::getRegisterName(int regNum) { + return _registers.getRegisterName(regNum); +} + +template bool UnwindCursor::isSignalFrame() { + return _isSignalFrame; +} + +#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + +#if defined(_LIBUNWIND_ARM_EHABI) +template +struct EHABISectionIterator { + typedef EHABISectionIterator _Self; + + typedef typename A::pint_t value_type; + typedef typename A::pint_t* pointer; + typedef typename A::pint_t& reference; + typedef size_t size_type; + typedef size_t difference_type; + + static _Self begin(A& addressSpace, const UnwindInfoSections& sects) { + return _Self(addressSpace, sects, 0); + } + static _Self end(A& addressSpace, const UnwindInfoSections& sects) { + return _Self(addressSpace, sects, + sects.arm_section_length / sizeof(EHABIIndexEntry)); + } + + EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i) + : _i(i), _addressSpace(&addressSpace), _sects(§s) {} + + _Self& operator++() { ++_i; return *this; } + _Self& operator+=(size_t a) { _i += a; return *this; } + _Self& operator--() { assert(_i > 0); --_i; return *this; } + _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; } + + _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; } + _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; } + + size_t operator-(const _Self& other) const { return _i - other._i; } + + bool operator==(const _Self& other) const { + assert(_addressSpace == other._addressSpace); + assert(_sects == other._sects); + return _i == other._i; + } + + bool operator!=(const _Self& other) const { + assert(_addressSpace == other._addressSpace); + assert(_sects == other._sects); + return _i != other._i; + } + + typename A::pint_t operator*() const { return functionAddress(); } + + typename A::pint_t functionAddress() const { + typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( + EHABIIndexEntry, _i, functionOffset); + return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr)); + } + + typename A::pint_t dataAddress() { + typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof( + EHABIIndexEntry, _i, data); + return indexAddr; + } + + private: + size_t _i; + A* _addressSpace; + const UnwindInfoSections* _sects; +}; + +namespace { + +template +EHABISectionIterator EHABISectionUpperBound( + EHABISectionIterator first, + EHABISectionIterator last, + typename A::pint_t value) { + size_t len = last - first; + while (len > 0) { + size_t l2 = len / 2; + EHABISectionIterator m = first + l2; + if (value < *m) { + len = l2; + } else { + first = ++m; + len -= l2 + 1; + } + } + return first; +} + +} + +template +bool UnwindCursor::getInfoFromEHABISection( + pint_t pc, + const UnwindInfoSections §s) { + EHABISectionIterator begin = + EHABISectionIterator::begin(_addressSpace, sects); + EHABISectionIterator end = + EHABISectionIterator::end(_addressSpace, sects); + if (begin == end) + return false; + + EHABISectionIterator itNextPC = EHABISectionUpperBound(begin, end, pc); + if (itNextPC == begin) + return false; + EHABISectionIterator itThisPC = itNextPC - 1; + + pint_t thisPC = itThisPC.functionAddress(); + // If an exception is thrown from a function, corresponding to the last entry + // in the table, we don't really know the function extent and have to choose a + // value for nextPC. Choosing max() will allow the range check during trace to + // succeed. + pint_t nextPC = (itNextPC == end) ? UINTPTR_MAX : itNextPC.functionAddress(); + pint_t indexDataAddr = itThisPC.dataAddress(); + + if (indexDataAddr == 0) + return false; + + uint32_t indexData = _addressSpace.get32(indexDataAddr); + if (indexData == UNW_EXIDX_CANTUNWIND) + return false; + + // If the high bit is set, the exception handling table entry is inline inside + // the index table entry on the second word (aka |indexDataAddr|). Otherwise, + // the table points at an offset in the exception handling table (section 5 + // EHABI). + pint_t exceptionTableAddr; + uint32_t exceptionTableData; + bool isSingleWordEHT; + if (indexData & 0x80000000) { + exceptionTableAddr = indexDataAddr; + // TODO(ajwong): Should this data be 0? + exceptionTableData = indexData; + isSingleWordEHT = true; + } else { + exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData); + exceptionTableData = _addressSpace.get32(exceptionTableAddr); + isSingleWordEHT = false; + } + + // Now we know the 3 things: + // exceptionTableAddr -- exception handler table entry. + // exceptionTableData -- the data inside the first word of the eht entry. + // isSingleWordEHT -- whether the entry is in the index. + unw_word_t personalityRoutine = 0xbadf00d; + bool scope32 = false; + uintptr_t lsda; + + // If the high bit in the exception handling table entry is set, the entry is + // in compact form (section 6.3 EHABI). + if (exceptionTableData & 0x80000000) { + // Grab the index of the personality routine from the compact form. + uint32_t choice = (exceptionTableData & 0x0f000000) >> 24; + uint32_t extraWords = 0; + switch (choice) { + case 0: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0; + extraWords = 0; + scope32 = false; + lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4); + break; + case 1: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1; + extraWords = (exceptionTableData & 0x00ff0000) >> 16; + scope32 = false; + lsda = exceptionTableAddr + (extraWords + 1) * 4; + break; + case 2: + personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2; + extraWords = (exceptionTableData & 0x00ff0000) >> 16; + scope32 = true; + lsda = exceptionTableAddr + (extraWords + 1) * 4; + break; + default: + _LIBUNWIND_ABORT("unknown personality routine"); + return false; + } + + if (isSingleWordEHT) { + if (extraWords != 0) { + _LIBUNWIND_ABORT("index inlined table detected but pr function " + "requires extra words"); + return false; + } + } + } else { + pint_t personalityAddr = + exceptionTableAddr + signExtendPrel31(exceptionTableData); + personalityRoutine = personalityAddr; + + // ARM EHABI # 6.2, # 9.2 + // + // +---- ehtp + // v + // +--------------------------------------+ + // | +--------+--------+--------+-------+ | + // | |0| prel31 to personalityRoutine | | + // | +--------+--------+--------+-------+ | + // | | N | unwind opcodes | | <-- UnwindData + // | +--------+--------+--------+-------+ | + // | | Word 2 unwind opcodes | | + // | +--------+--------+--------+-------+ | + // | ... | + // | +--------+--------+--------+-------+ | + // | | Word N unwind opcodes | | + // | +--------+--------+--------+-------+ | + // | | LSDA | | <-- lsda + // | | ... | | + // | +--------+--------+--------+-------+ | + // +--------------------------------------+ + + uint32_t *UnwindData = reinterpret_cast(exceptionTableAddr) + 1; + uint32_t FirstDataWord = *UnwindData; + size_t N = ((FirstDataWord >> 24) & 0xff); + size_t NDataWords = N + 1; + lsda = reinterpret_cast(UnwindData + NDataWords); + } + + _info.start_ip = thisPC; + _info.end_ip = nextPC; + _info.handler = personalityRoutine; + _info.unwind_info = exceptionTableAddr; + _info.lsda = lsda; + // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0. + _info.flags = (isSingleWordEHT ? 1 : 0) | (scope32 ? 0x2 : 0); // Use enum? + + return true; +} +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +template +bool UnwindCursor::getInfoFromFdeCie( + const typename CFI_Parser::FDE_Info &fdeInfo, + const typename CFI_Parser::CIE_Info &cieInfo, pint_t pc, + uintptr_t dso_base) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, + R::getArch(), &prolog)) { + // Save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + // Some frameless functions need SP altered when resuming in function, so + // propagate spExtraArgSize. + _info.gp = prolog.spExtraArgSize; + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = static_cast(fdeInfo.fdeLength); + _info.extra = static_cast(dso_base); + return true; + } + return false; +} + +template +bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, + const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + bool foundFDE = false; + bool foundInCache = false; + // If compact encoding table gave offset into dwarf section, go directly there + if (fdeSectionOffsetHint != 0) { + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + sects.dwarf_section_length, + sects.dwarf_section + fdeSectionOffsetHint, + &fdeInfo, &cieInfo); + } +#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (!foundFDE && (sects.dwarf_index_section != 0)) { + foundFDE = EHHeaderParser::findFDE( + _addressSpace, pc, sects.dwarf_index_section, + (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo); + } +#endif + if (!foundFDE) { + // otherwise, search cache of previously found FDEs. + pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); + if (cachedFDE != 0) { + foundFDE = + CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + sects.dwarf_section_length, + cachedFDE, &fdeInfo, &cieInfo); + foundInCache = foundFDE; + } + } + if (!foundFDE) { + // Still not found, do full scan of __eh_frame section. + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); + } + if (foundFDE) { + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) { + // Add to cache (to make next lookup faster) if we had no hint + // and there was no index. + if (!foundInCache && (fdeSectionOffsetHint == 0)) { + #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) + if (sects.dwarf_index_section == 0) + #endif + DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } + return true; + } + } + //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc); + return false; +} +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + + +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) +template +bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s) { + const bool log = false; + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", + (uint64_t)pc, (uint64_t)sects.dso_base); + + const UnwindSectionHeader sectionHeader(_addressSpace, + sects.compact_unwind_section); + if (sectionHeader.version() != UNWIND_SECTION_VERSION) + return false; + + // do a binary search of top level index to find page with unwind info + pint_t targetFunctionOffset = pc - sects.dso_base; + const UnwindSectionIndexArray topIndex(_addressSpace, + sects.compact_unwind_section + + sectionHeader.indexSectionOffset()); + uint32_t low = 0; + uint32_t high = sectionHeader.indexCount(); + uint32_t last = high - 1; + while (low < high) { + uint32_t mid = (low + high) / 2; + //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", + //mid, low, high, topIndex.functionOffset(mid)); + if (topIndex.functionOffset(mid) <= targetFunctionOffset) { + if ((mid == last) || + (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); + const uint32_t firstLevelNextPageFunctionOffset = + topIndex.functionOffset(low + 1); + const pint_t secondLevelAddr = + sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); + const pint_t lsdaArrayStartAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); + const pint_t lsdaArrayEndAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); + if (log) + fprintf(stderr, "\tfirst level search for result index=%d " + "to secondLevelAddr=0x%llX\n", + low, (uint64_t) secondLevelAddr); + // do a binary search of second level page index + uint32_t encoding = 0; + pint_t funcStart = 0; + pint_t funcEnd = 0; + pint_t lsda = 0; + pint_t personality = 0; + uint32_t pageKind = _addressSpace.get32(secondLevelAddr); + if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { + // regular page + UnwindSectionRegularPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionRegularArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " + "regular page starting at secondLevelAddr=0x%llX\n", + (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); + low = 0; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { + if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { + // at end of table + low = mid; + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + break; + } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { + // next is too big, so we found it + low = mid; + funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + encoding = pageIndex.encoding(low); + funcStart = pageIndex.functionOffset(low) + sects.dso_base; + if (pc < funcStart) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + if (pc > funcEnd) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { + // compressed page + UnwindSectionCompressedPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionCompressedArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + const uint32_t targetFunctionPageOffset = + (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search of compressed page starting at " + "secondLevelAddr=0x%llX\n", + (uint64_t) secondLevelAddr); + low = 0; + last = pageHeader.entryCount() - 1; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { + if ((mid == last) || + (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + + sects.dso_base; + if (low < last) + funcEnd = + pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset + + sects.dso_base; + else + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + if (pc < funcStart) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX " + "not in second level compressed unwind table. " + "funcStart=0x%llX", + (uint64_t) pc, (uint64_t) funcStart); + return false; + } + if (pc > funcEnd) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX " + "not in second level compressed unwind table. " + "funcEnd=0x%llX", + (uint64_t) pc, (uint64_t) funcEnd); + return false; + } + uint16_t encodingIndex = pageIndex.encodingIndex(low); + if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { + // encoding is in common table in section header + encoding = _addressSpace.get32( + sects.compact_unwind_section + + sectionHeader.commonEncodingsArraySectionOffset() + + encodingIndex * sizeof(uint32_t)); + } else { + // encoding is in page specific table + uint16_t pageEncodingIndex = + encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); + encoding = _addressSpace.get32(secondLevelAddr + + pageHeader.encodingsPageOffset() + + pageEncodingIndex * sizeof(uint32_t)); + } + } else { + _LIBUNWIND_DEBUG_LOG( + "malformed __unwind_info at 0x%0llX bad second level page", + (uint64_t)sects.compact_unwind_section); + return false; + } + + // look up LSDA, if encoding says function has one + if (encoding & UNWIND_HAS_LSDA) { + UnwindSectionLsdaArray lsdaIndex(_addressSpace, lsdaArrayStartAddr); + uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); + low = 0; + high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / + sizeof(unwind_info_section_header_lsda_index_entry); + // binary search looks for entry with exact match for functionOffset + if (log) + fprintf(stderr, + "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", + funcStartOffset); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (lsdaIndex.functionOffset(mid) == funcStartOffset) { + lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; + break; + } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { + low = mid + 1; + } else { + high = mid; + } + } + if (lsda == 0) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " + "pc=0x%0llX, but lsda table has no entry", + encoding, (uint64_t) pc); + return false; + } + } + + // extract personality routine, if encoding says function has one + uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> + (__builtin_ctz(UNWIND_PERSONALITY_MASK)); + if (personalityIndex != 0) { + --personalityIndex; // change 1-based to zero-based index + if (personalityIndex >= sectionHeader.personalityArrayCount()) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " + "but personality table has only %d entries", + encoding, personalityIndex, + sectionHeader.personalityArrayCount()); + return false; + } + int32_t personalityDelta = (int32_t)_addressSpace.get32( + sects.compact_unwind_section + + sectionHeader.personalityArraySectionOffset() + + personalityIndex * sizeof(uint32_t)); + pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; + personality = _addressSpace.getP(personalityPointer); + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "personalityDelta=0x%08X, personality=0x%08llX\n", + (uint64_t) pc, personalityDelta, (uint64_t) personality); + } + + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", + (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); + _info.start_ip = funcStart; + _info.end_ip = funcEnd; + _info.lsda = lsda; + _info.handler = personality; + _info.gp = 0; + _info.flags = 0; + _info.format = encoding; + _info.unwind_info = 0; + _info.unwind_info_size = 0; + _info.extra = sects.dso_base; + return true; +} +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +template +bool UnwindCursor::getInfoFromSEH(pint_t pc) { + pint_t base; + RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base); + if (!unwindEntry) { + _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc); + return false; + } + _info.gp = 0; + _info.flags = 0; + _info.format = 0; + _info.unwind_info_size = sizeof(RUNTIME_FUNCTION); + _info.unwind_info = reinterpret_cast(unwindEntry); + _info.extra = base; + _info.start_ip = base + unwindEntry->BeginAddress; +#ifdef _LIBUNWIND_TARGET_X86_64 + _info.end_ip = base + unwindEntry->EndAddress; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + UNWIND_INFO *xdata = reinterpret_cast(base + unwindEntry->UnwindData); + if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) { + // The personality is given in the UNWIND_INFO itself. The LSDA immediately + // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit + // these structures.) + // N.B. UNWIND_INFO structs are DWORD-aligned. + uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1; + const uint32_t *handler = reinterpret_cast(&xdata->UnwindCodes[lastcode]); + _info.lsda = reinterpret_cast(handler+1); + if (*handler) { + _info.handler = reinterpret_cast(__libunwind_seh_personality); + } else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } +#elif defined(_LIBUNWIND_TARGET_ARM) + _info.end_ip = _info.start_ip + unwindEntry->FunctionLength; + _info.lsda = 0; // FIXME + _info.handler = 0; // FIXME +#endif + setLastPC(pc); + return true; +} +#endif + + +template +void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + _isSigReturn = false; +#endif + + pint_t pc = static_cast(this->getReg(UNW_REG_IP)); +#if defined(_LIBUNWIND_ARM_EHABI) + // Remove the thumb bit so the IP represents the actual instruction address. + // This matches the behaviour of _Unwind_GetIP on arm. + pc &= (pint_t)~0x1; +#endif + + // Exit early if at the top of the stack. + if (pc == 0) { + _unwindInfoMissing = true; + return; + } + + // If the last line of a function is a "throw" the compiler sometimes + // emits no instructions after the call to __cxa_throw. This means + // the return address is actually the start of the next function. + // To disambiguate this, back up the pc when we know it is a return + // address. + if (isReturnAddress) + --pc; + + // Ask address space object to find unwind sections for this pc. + UnwindInfoSections sects; + if (_addressSpace.findUnwindSections(pc, sects)) { +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + // If there is a compact unwind encoding table, look there first. + if (sects.compact_unwind_section != 0) { + if (this->getInfoFromCompactEncodingSection(pc, sects)) { + #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // Found info in table, done unless encoding says to use dwarf. + uint32_t dwarfOffset; + if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { + if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { + // found info in dwarf, done + return; + } + } + #endif + // If unwind table has entry, but entry says there is no unwind info, + // record that we have no unwind info. + if (_info.format == 0) + _unwindInfoMissing = true; + return; + } + } +#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + // If there is SEH unwind info, look there next. + if (this->getInfoFromSEH(pc)) + return; +#endif + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // If there is dwarf unwind info, look there next. + if (sects.dwarf_section != 0) { + if (this->getInfoFromDwarfSection(pc, sects)) { + // found info in dwarf, done + return; + } + } +#endif + +#if defined(_LIBUNWIND_ARM_EHABI) + // If there is ARM EHABI unwind info, look there next. + if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects)) + return; +#endif + } + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + // There is no static unwind info for this pc. Look to see if an FDE was + // dynamically registered for it. + pint_t cachedFDE = DwarfFDECache::findFDE(DwarfFDECache::kSearchAll, + pc); + if (cachedFDE != 0) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) + return; + } + + // Lastly, ask AddressSpace object about platform specific ways to locate + // other FDEs. + pint_t fde; + if (_addressSpace.findOtherFDE(pc, fde)) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { + // Double check this FDE is for a function that includes the pc. + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) + if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0)) + return; + } + } +#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + if (setInfoForSigReturn()) + return; +#endif + + // no unwind info, flag that we can't reliably unwind + _unwindInfoMissing = true; +} + +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) +template +bool UnwindCursor::setInfoForSigReturn(Registers_arm64 &) { + // Look for the sigreturn trampoline. The trampoline's body is two + // specific instructions (see below). Typically the trampoline comes from the + // vDSO[1] (i.e. the __kernel_rt_sigreturn function). A libc might provide its + // own restorer function, though, or user-mode QEMU might write a trampoline + // onto the stack. + // + // This special code path is a fallback that is only used if the trampoline + // lacks proper (e.g. DWARF) unwind info. On AArch64, a new DWARF register + // constant for the PC needs to be defined before DWARF can handle a signal + // trampoline. This code may segfault if the target PC is unreadable, e.g.: + // - The PC points at a function compiled without unwind info, and which is + // part of an execute-only mapping (e.g. using -Wl,--execute-only). + // - The PC is invalid and happens to point to unreadable or unmapped memory. + // + // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S + const pint_t pc = static_cast(this->getReg(UNW_REG_IP)); + // Look for instructions: mov x8, #0x8b; svc #0x0 + if (_addressSpace.get32(pc) == 0xd2801168 && + _addressSpace.get32(pc + 4) == 0xd4000001) { + _info = {}; + _isSigReturn = true; + return true; + } + return false; +} + +template +int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) { + // In the signal trampoline frame, sp points to an rt_sigframe[1], which is: + // - 128-byte siginfo struct + // - ucontext struct: + // - 8-byte long (uc_flags) + // - 8-byte pointer (uc_link) + // - 24-byte stack_t + // - 128-byte signal set + // - 8 bytes of padding because sigcontext has 16-byte alignment + // - sigcontext/mcontext_t + // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c + const pint_t kOffsetSpToSigcontext = (128 + 8 + 8 + 24 + 128 + 8); // 304 + + // Offsets from sigcontext to each register. + const pint_t kOffsetGprs = 8; // offset to "__u64 regs[31]" field + const pint_t kOffsetSp = 256; // offset to "__u64 sp" field + const pint_t kOffsetPc = 264; // offset to "__u64 pc" field + + pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext; + + for (int i = 0; i <= 30; ++i) { + uint64_t value = _addressSpace.get64(sigctx + kOffsetGprs + + static_cast(i * 8)); + _registers.setRegister(UNW_AARCH64_X0 + i, value); + } + _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp)); + _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc)); + _isSignalFrame = true; + return UNW_STEP_SUCCESS; +} +#endif // defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + +template +int UnwindCursor::step() { + // Bottom of stack is defined is when unwind info cannot be found. + if (_unwindInfoMissing) + return UNW_STEP_END; + + // Use unwinding info to modify register set as if function returned. + int result; +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64) + if (_isSigReturn) { + result = this->stepThroughSigReturn(); + } else +#endif + { +#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) + result = this->stepWithCompactEncoding(); +#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) + result = this->stepWithSEHData(); +#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + result = this->stepWithDwarfFDE(); +#elif defined(_LIBUNWIND_ARM_EHABI) + result = this->stepWithEHABI(); +#else + #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \ + _LIBUNWIND_SUPPORT_SEH_UNWIND or \ + _LIBUNWIND_SUPPORT_DWARF_UNWIND or \ + _LIBUNWIND_ARM_EHABI +#endif + } + + // update info based on new PC + if (result == UNW_STEP_SUCCESS) { + this->setInfoBasedOnIPRegister(true); + if (_unwindInfoMissing) + return UNW_STEP_END; + } + + return result; +} + +template +void UnwindCursor::getInfo(unw_proc_info_t *info) { + if (_unwindInfoMissing) + memset(info, 0, sizeof(*info)); + else + *info = _info; +} + +template +bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, + unw_word_t *offset) { + return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), + buf, bufLen, offset); +} + +#if defined(_LIBUNWIND_USE_CET) +extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) { + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->get_registers(); +} +#endif +} // namespace libunwind + +#endif // __UNWINDCURSOR_HPP__ diff --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c new file mode 100644 index 0000000000..4172540ef0 --- /dev/null +++ b/libunwind/src/UnwindLevel1-gcc-ext.c @@ -0,0 +1,317 @@ +//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements gcc extensions to the C++ ABI Exception Handling Level 1. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "libunwind_ext.h" +#include "libunwind.h" +#include "Unwind-EHABI.h" +#include "unwind.h" + +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + +#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) +#define PRIVATE_1 private_[0] +#elif defined(_LIBUNWIND_ARM_EHABI) +#define PRIVATE_1 unwinder_cache.reserved1 +#else +#define PRIVATE_1 private_1 +#endif + +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API( + "_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR, + (void *)exception_object, (intptr_t)exception_object->PRIVATE_1); + + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception + if (exception_object->PRIVATE_1 == 0) { + return _Unwind_RaiseException(exception_object); + // Will return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate(). + } + + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_Resume(exception_object); + _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" + " which unexpectedly returned"); +} + +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); +} + + +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); +} + + +/// Scans unwind information to find the function that contains the +/// specified code address "pc". +_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { + _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc); + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); + __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc); + if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) + return (void *)(intptr_t) info.start_ip; + else + return NULL; +} + +/// Walk every frame and call trace function at each one. If trace function +/// returns anything other than _URC_NO_REASON, then walk is terminated. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { + unw_cursor_t cursor; + unw_context_t uc; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); + + _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)", + (void *)(uintptr_t)callback); + +#if defined(_LIBUNWIND_ARM_EHABI) + // Create a mock exception object for force unwinding. + _Unwind_Exception ex; + memset(&ex, '\0', sizeof(ex)); + strcpy((char *)&ex.exception_class, "CLNGUNW"); +#endif + + // walk each frame + while (true) { + _Unwind_Reason_Code result; + +#if !defined(_LIBUNWIND_ARM_EHABI) + // ask libunwind to get next frame (skip over first frame which is + // _Unwind_Backtrace()) + if (__unw_step(&cursor) <= 0) { + _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached " + "bottom of stack, returning %d", + _URC_END_OF_STACK); + return _URC_END_OF_STACK; + } +#else + // Get the information for this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) { + return _URC_END_OF_STACK; + } + + // Update the pr_cache in the mock exception object. + const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info; + ex.pr_cache.fnstart = frameInfo.start_ip; + ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo; + ex.pr_cache.additional= frameInfo.flags; + + struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor; + // Get and call the personality function to unwind the frame. + _Unwind_Personality_Fn handler = (_Unwind_Personality_Fn)frameInfo.handler; + if (handler == NULL) { + return _URC_END_OF_STACK; + } + if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) != + _URC_CONTINUE_UNWIND) { + return _URC_END_OF_STACK; + } +#endif // defined(_LIBUNWIND_ARM_EHABI) + + // debugging + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_proc_info_t frame; + unw_word_t offset; + __unw_get_proc_name(&cursor, functionName, 512, &offset); + __unw_get_proc_info(&cursor, &frame); + _LIBUNWIND_TRACE_UNWINDING( + " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p", + frame.start_ip, functionName, frame.lsda, + (void *)&cursor); + } + + // call trace function with this frame + result = (*callback)((struct _Unwind_Context *)(&cursor), ref); + if (result != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + " _backtrace: ended because callback returned %d", result); + return result; + } + } +} + + +/// Find DWARF unwind info for an address 'pc' in some function. +_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, + struct dwarf_eh_bases *bases) { + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + __unw_getcontext(&uc); + __unw_init_local(&cursor, &uc); + __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc); + __unw_get_proc_info(&cursor, &info); + bases->tbase = (uintptr_t)info.extra; + bases->dbase = 0; // dbase not used on Mac OS X + bases->func = (uintptr_t)info.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc, + (void *)(intptr_t) info.unwind_info); + return (void *)(intptr_t) info.unwind_info; +} + +/// Returns the CFA (call frame area, or stack pointer at start of function) +/// for the current context. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, UNW_REG_SP, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return (uintptr_t)result; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context); + int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context); + // Negative means some kind of error (probably UNW_ENOINFO), but we have no + // good way to report that, and this maintains backward compatibility with the + // implementation that hard-coded zero in every case, even signal frames. + if (isSignalFrame <= 0) + *ipBefore = 0; + else + *ipBefore = 1; + return _Unwind_GetIP(context); +} + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +/// Called by programs with dynamic code generators that want +/// to register a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __register_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__register_frame(%p)", fde); + __unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde); +} + + +/// Called by programs with dynamic code generators that want +/// to unregister a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde); + __unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde); +} + + +// The following register/deregister functions are gcc extensions. +// They have existed on Mac OS X, but have never worked because Mac OS X +// before 10.6 used keymgr to track known FDEs, but these functions +// never got updated to use keymgr. +// For now, we implement these as do-nothing functions to keep any existing +// applications working. We also add the not in 10.6 symbol so that nwe +// application won't be able to use them. + +#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS) +_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, + void *tb, void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)", + fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde, + void *ob, void *tb, + void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_table_bases" + "(%p,%p, %p, %p)", fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde); + // do nothing, this function never worked in Mac OS X + return NULL; +} + +_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde); + // do nothing, this function never worked in Mac OS X + return NULL; +} +#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS) + +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) + +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c new file mode 100644 index 0000000000..9203ac771f --- /dev/null +++ b/libunwind/src/UnwindLevel1.c @@ -0,0 +1,561 @@ +//===------------------------- UnwindLevel1.c -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements C++ ABI Exception Handling Level 1 as documented at: +// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +// using libunwind +// +//===----------------------------------------------------------------------===// + +// ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are +// defining inline functions to delegate the function calls to +// _Unwind_VRS_{Get,Set}(). However, some applications might declare the +// function protetype directly (instead of including ), thus we need +// to export these functions from libunwind.so as well. +#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1 + +#include +#include +#include +#include +#include +#include + +#include "cet_unwind.h" +#include "config.h" +#include "libunwind.h" +#include "libunwind_ext.h" +#include "unwind.h" + +#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) + +#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND + +// When CET is enabled, each "call" instruction will push return address to +// CET shadow stack, each "ret" instruction will pop current CET shadow stack +// top and compare it with target address which program will return. +// In exception handing, some stack frames will be skipped before jumping to +// landing pad and we must adjust CET shadow stack accordingly. +// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we +// directly jump to __libunwind_Registerts_x86/x86_64_jumpto instead of using +// a regular function call to avoid pushing to CET shadow stack again. +#if !defined(_LIBUNWIND_USE_CET) +#define __unw_phase2_resume(cursor, fn) __unw_resume((cursor)) +#elif defined(_LIBUNWIND_TARGET_I386) +#define __unw_phase2_resume(cursor, fn) \ + do { \ + _LIBUNWIND_POP_CET_SSP((fn)); \ + void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ + void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + __asm__ volatile("push %%edi\n\t" \ + "sub $4, %%esp\n\t" \ + "jmp *%%edx\n\t" :: "D"(cetRegContext), \ + "d"(cetJumpAddress)); \ + } while (0) +#elif defined(_LIBUNWIND_TARGET_X86_64) +#define __unw_phase2_resume(cursor, fn) \ + do { \ + _LIBUNWIND_POP_CET_SSP((fn)); \ + void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ + void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \ + "d"(cetJumpAddress)); \ + } while (0) +#endif + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + __unw_init_local(cursor, uc); + + // Walk each frame looking for a place to stop. + while (true) { + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = __unw_step(cursor); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_step failed => " + "_URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + unw_word_t sp; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", + (void *)exception_object, pc, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } +#endif + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + __unw_get_reg(cursor, UNW_REG_SP, &sp); + exception_object->private_2 = (uintptr_t)sp; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", + (void *)exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + + +static _Unwind_Reason_Code +unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { + __unw_init_local(cursor, uc); + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", + (void *)exception_object); + + // uc is initialized by __unw_getcontext in the parent frame. The first stack + // frame walked is unwind_phase2. + unsigned framesWalked = 1; + // Walk each frame until we reach where search phase said to stop. + while (true) { + + // Ask libunwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = __unw_step(cursor); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step() reached " + "bottom => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_step failed => " + "_URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + __unw_get_reg(cursor, UNW_REG_SP, &sp); + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR + ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, + functionName, sp, frameInfo.lsda, + frameInfo.handler); + } +#endif + + ++framesWalked; + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler); + _Unwind_Action action = _UA_CLEANUP_PHASE; + if (sp == exception_object->private_2) { + // Tell personality this was the frame it marked in phase 1. + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + } + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", + (void *)exception_object); + if (sp == exception_object->private_2) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now in phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", + (void *)exception_object); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + __unw_get_reg(cursor, UNW_REG_IP, &pc); + __unw_get_reg(cursor, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%" PRIxPTR + ", sp=0x%" PRIxPTR, + (void *)exception_object, pc, sp); + } + + __unw_phase2_resume(cursor, framesWalked); + // __unw_phase2_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor, + _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + __unw_init_local(cursor, uc); + + // uc is initialized by __unw_getcontext in the parent frame. The first stack + // frame walked is unwind_phase2_forced. + unsigned framesWalked = 1; + // Walk each frame until we reach where search phase said to stop + while (__unw_step(cursor) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " + "failed => _URC_END_OF_STACK", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + +#ifndef NDEBUG + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionBuf[512]; + const char *functionName = functionBuf; + unw_word_t offset; + if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), + &offset) != UNW_ESUCCESS) || + (frameInfo.start_ip + offset > frameInfo.end_ip)) + functionName = ".anonymous."; + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR + ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, + (void *)exception_object, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } +#endif + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", + (void *)exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", + (void *)exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + ++framesWalked; + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + _Unwind_Personality_Fn p = + (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", + (void *)exception_object, (void *)(uintptr_t)p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_CONTINUE_UNWIND", + (void *)exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned " + "_URC_INSTALL_CONTEXT", + (void *)exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + __unw_phase2_resume(cursor, framesWalked); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR", + (void *)exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK", + (void *)exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(cursor), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + + +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", + (void *)exception_object); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + exception_object->private_1 = 0; + exception_object->private_2 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(&uc, &cursor, exception_object); +} + + + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + if (exception_object->private_1 != 0) + unwind_phase2_forced(&uc, &cursor, exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(&uc, &cursor, exception_object); + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + + + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", + (void *)exception_object, (void *)(uintptr_t)stop); + unw_context_t uc; + unw_cursor_t cursor; + __unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_1 = (uintptr_t) stop; + exception_object->private_2 = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter); +} + + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API( + "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + if (result != 0) { + if (*((uint8_t *)result) != 0xFF) + _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF", + result); + } + return result; +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return result; +} + +#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(_Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", + (void *)exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetGR(struct _Unwind_Context *context, int index) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, index, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR, + (void *)context, index, result); + return (uintptr_t)result; +} + +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR + ")", + (void *)context, index, value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + __unw_set_reg(cursor, index, value); +} + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + __unw_get_reg(cursor, UNW_REG_IP, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, + (void *)context, result); + return (uintptr_t)result; +} + +/// Called by personality handler during phase 2 to alter instruction pointer, +/// such as setting where the landing pad is, so _Unwind_Resume() will +/// start executing in the landing pad. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")", + (void *)context, value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + __unw_set_reg(cursor, UNW_REG_IP, value); +} + +#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S new file mode 100644 index 0000000000..955ec3355f --- /dev/null +++ b/libunwind/src/UnwindRegistersRestore.S @@ -0,0 +1,1167 @@ +//===-------------------- UnwindRegistersRestore.S ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "assembly.h" + + .text + +#if !defined(__USING_SJLJ_EXCEPTIONS__) + +#if defined(__i386__) +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto) +# +# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + + + _LIBUNWIND_CET_ENDBR + movl 4(%esp), %eax + # set up eax and ret on new stack location + movl 28(%eax), %edx # edx holds new stack pointer + subl $8,%edx + movl %edx, 28(%eax) + movl 0(%eax), %ebx + movl %ebx, 0(%edx) + movl 40(%eax), %ebx + movl %ebx, 4(%edx) + # we now have ret and eax pushed onto where new stack will be + # restore all registers + movl 4(%eax), %ebx + movl 8(%eax), %ecx + movl 12(%eax), %edx + movl 16(%eax), %edi + movl 20(%eax), %esi + movl 24(%eax), %ebp + movl 28(%eax), %esp + # skip ss + # skip eflags + pop %eax # eax was already pushed on new stack + pop %ecx + jmp *%ecx + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + +#elif defined(__x86_64__) + +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto) +# +# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); +# +#if defined(_WIN64) +# On entry, thread_state pointer is in rcx; move it into rdi +# to share restore code below. Since this routine restores and +# overwrites all registers, we can use the same registers for +# pointers and temporaries as on unix even though win64 normally +# mustn't clobber some of them. + movq %rcx, %rdi +#else +# On entry, thread_state pointer is in rdi +#endif + + _LIBUNWIND_CET_ENDBR + movq 56(%rdi), %rax # rax holds new stack pointer + subq $16, %rax + movq %rax, 56(%rdi) + movq 32(%rdi), %rbx # store new rdi on new stack + movq %rbx, 0(%rax) + movq 128(%rdi), %rbx # store new rip on new stack + movq %rbx, 8(%rax) + # restore all registers + movq 0(%rdi), %rax + movq 8(%rdi), %rbx + movq 16(%rdi), %rcx + movq 24(%rdi), %rdx + # restore rdi later + movq 40(%rdi), %rsi + movq 48(%rdi), %rbp + # restore rsp later + movq 64(%rdi), %r8 + movq 72(%rdi), %r9 + movq 80(%rdi), %r10 + movq 88(%rdi), %r11 + movq 96(%rdi), %r12 + movq 104(%rdi), %r13 + movq 112(%rdi), %r14 + movq 120(%rdi), %r15 + # skip rflags + # skip cs + # skip fs + # skip gs + +#if defined(_WIN64) + movdqu 176(%rdi),%xmm0 + movdqu 192(%rdi),%xmm1 + movdqu 208(%rdi),%xmm2 + movdqu 224(%rdi),%xmm3 + movdqu 240(%rdi),%xmm4 + movdqu 256(%rdi),%xmm5 + movdqu 272(%rdi),%xmm6 + movdqu 288(%rdi),%xmm7 + movdqu 304(%rdi),%xmm8 + movdqu 320(%rdi),%xmm9 + movdqu 336(%rdi),%xmm10 + movdqu 352(%rdi),%xmm11 + movdqu 368(%rdi),%xmm12 + movdqu 384(%rdi),%xmm13 + movdqu 400(%rdi),%xmm14 + movdqu 416(%rdi),%xmm15 +#endif + movq 56(%rdi), %rsp # cut back rsp to new location + pop %rdi # rdi was saved here earlier + pop %rcx + jmpq *%rcx + + +#elif defined(__powerpc64__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv) +// +// void libunwind::Registers_ppc64::jumpto() +// +// On entry: +// thread_state pointer is in r3 +// + +// load register (GPR) +#define PPC64_LR(n) \ + ld n, (8 * (n + 2))(3) + + // restore integral registers + // skip r0 for now + // skip r1 for now + PPC64_LR(2) + // skip r3 for now + // skip r4 for now + // skip r5 for now + PPC64_LR(6) + PPC64_LR(7) + PPC64_LR(8) + PPC64_LR(9) + PPC64_LR(10) + PPC64_LR(11) + PPC64_LR(12) + PPC64_LR(13) + PPC64_LR(14) + PPC64_LR(15) + PPC64_LR(16) + PPC64_LR(17) + PPC64_LR(18) + PPC64_LR(19) + PPC64_LR(20) + PPC64_LR(21) + PPC64_LR(22) + PPC64_LR(23) + PPC64_LR(24) + PPC64_LR(25) + PPC64_LR(26) + PPC64_LR(27) + PPC64_LR(28) + PPC64_LR(29) + PPC64_LR(30) + PPC64_LR(31) + +#if defined(__VSX__) + + // restore VS registers + // (note that this also restores floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi 4, 3, PPC64_OFFS_FP + +// load VS register +#define PPC64_LVS(n) \ + lxvd2x n, 0, 4 ;\ + addi 4, 4, 16 + + // restore the first 32 VS regs (and also all floating point regs) + PPC64_LVS(0) + PPC64_LVS(1) + PPC64_LVS(2) + PPC64_LVS(3) + PPC64_LVS(4) + PPC64_LVS(5) + PPC64_LVS(6) + PPC64_LVS(7) + PPC64_LVS(8) + PPC64_LVS(9) + PPC64_LVS(10) + PPC64_LVS(11) + PPC64_LVS(12) + PPC64_LVS(13) + PPC64_LVS(14) + PPC64_LVS(15) + PPC64_LVS(16) + PPC64_LVS(17) + PPC64_LVS(18) + PPC64_LVS(19) + PPC64_LVS(20) + PPC64_LVS(21) + PPC64_LVS(22) + PPC64_LVS(23) + PPC64_LVS(24) + PPC64_LVS(25) + PPC64_LVS(26) + PPC64_LVS(27) + PPC64_LVS(28) + PPC64_LVS(29) + PPC64_LVS(30) + PPC64_LVS(31) + + // use VRSAVE to conditionally restore the remaining VS regs, + // that are where the V regs are mapped + + ld 5, PPC64_OFFS_VRSAVE(3) // test VRsave + cmpwi 5, 0 + beq Lnovec + +// conditionally load VS +#define PPC64_CLVS_BOTTOM(n) \ + beq Ldone##n ;\ + addi 4, 3, PPC64_OFFS_FP + n * 16 ;\ + lxvd2x n, 0, 4 ;\ +Ldone##n: + +#define PPC64_CLVSl(n) \ + andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n)) ;\ +PPC64_CLVS_BOTTOM(n) + +#define PPC64_CLVSh(n) \ + andi. 0, 5, (1 PPC_LEFT_SHIFT(63-n)) ;\ +PPC64_CLVS_BOTTOM(n) + + PPC64_CLVSl(32) + PPC64_CLVSl(33) + PPC64_CLVSl(34) + PPC64_CLVSl(35) + PPC64_CLVSl(36) + PPC64_CLVSl(37) + PPC64_CLVSl(38) + PPC64_CLVSl(39) + PPC64_CLVSl(40) + PPC64_CLVSl(41) + PPC64_CLVSl(42) + PPC64_CLVSl(43) + PPC64_CLVSl(44) + PPC64_CLVSl(45) + PPC64_CLVSl(46) + PPC64_CLVSl(47) + PPC64_CLVSh(48) + PPC64_CLVSh(49) + PPC64_CLVSh(50) + PPC64_CLVSh(51) + PPC64_CLVSh(52) + PPC64_CLVSh(53) + PPC64_CLVSh(54) + PPC64_CLVSh(55) + PPC64_CLVSh(56) + PPC64_CLVSh(57) + PPC64_CLVSh(58) + PPC64_CLVSh(59) + PPC64_CLVSh(60) + PPC64_CLVSh(61) + PPC64_CLVSh(62) + PPC64_CLVSh(63) + +#else + +// load FP register +#define PPC64_LF(n) \ + lfd n, (PPC64_OFFS_FP + n * 16)(3) + + // restore float registers + PPC64_LF(0) + PPC64_LF(1) + PPC64_LF(2) + PPC64_LF(3) + PPC64_LF(4) + PPC64_LF(5) + PPC64_LF(6) + PPC64_LF(7) + PPC64_LF(8) + PPC64_LF(9) + PPC64_LF(10) + PPC64_LF(11) + PPC64_LF(12) + PPC64_LF(13) + PPC64_LF(14) + PPC64_LF(15) + PPC64_LF(16) + PPC64_LF(17) + PPC64_LF(18) + PPC64_LF(19) + PPC64_LF(20) + PPC64_LF(21) + PPC64_LF(22) + PPC64_LF(23) + PPC64_LF(24) + PPC64_LF(25) + PPC64_LF(26) + PPC64_LF(27) + PPC64_LF(28) + PPC64_LF(29) + PPC64_LF(30) + PPC64_LF(31) + +#if defined(__ALTIVEC__) + // restore vector registers if any are in use + ld 5, PPC64_OFFS_VRSAVE(3) // test VRsave + cmpwi 5, 0 + beq Lnovec + + subi 4, 1, 16 + // r4 is now a 16-byte aligned pointer into the red zone + // the _vectorScalarRegisters may not be 16-byte aligned + // so copy via red zone temp buffer + +#define PPC64_CLV_UNALIGNED_BOTTOM(n) \ + beq Ldone##n ;\ + ld 0, (PPC64_OFFS_V + n * 16)(3) ;\ + std 0, 0(4) ;\ + ld 0, (PPC64_OFFS_V + n * 16 + 8)(3) ;\ + std 0, 8(4) ;\ + lvx n, 0, 4 ;\ +Ldone ## n: + +#define PPC64_CLV_UNALIGNEDl(n) \ + andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + +#define PPC64_CLV_UNALIGNEDh(n) \ + andi. 0, 5, (1 PPC_LEFT_SHIFT(31-n)) ;\ +PPC64_CLV_UNALIGNED_BOTTOM(n) + + PPC64_CLV_UNALIGNEDl(0) + PPC64_CLV_UNALIGNEDl(1) + PPC64_CLV_UNALIGNEDl(2) + PPC64_CLV_UNALIGNEDl(3) + PPC64_CLV_UNALIGNEDl(4) + PPC64_CLV_UNALIGNEDl(5) + PPC64_CLV_UNALIGNEDl(6) + PPC64_CLV_UNALIGNEDl(7) + PPC64_CLV_UNALIGNEDl(8) + PPC64_CLV_UNALIGNEDl(9) + PPC64_CLV_UNALIGNEDl(10) + PPC64_CLV_UNALIGNEDl(11) + PPC64_CLV_UNALIGNEDl(12) + PPC64_CLV_UNALIGNEDl(13) + PPC64_CLV_UNALIGNEDl(14) + PPC64_CLV_UNALIGNEDl(15) + PPC64_CLV_UNALIGNEDh(16) + PPC64_CLV_UNALIGNEDh(17) + PPC64_CLV_UNALIGNEDh(18) + PPC64_CLV_UNALIGNEDh(19) + PPC64_CLV_UNALIGNEDh(20) + PPC64_CLV_UNALIGNEDh(21) + PPC64_CLV_UNALIGNEDh(22) + PPC64_CLV_UNALIGNEDh(23) + PPC64_CLV_UNALIGNEDh(24) + PPC64_CLV_UNALIGNEDh(25) + PPC64_CLV_UNALIGNEDh(26) + PPC64_CLV_UNALIGNEDh(27) + PPC64_CLV_UNALIGNEDh(28) + PPC64_CLV_UNALIGNEDh(29) + PPC64_CLV_UNALIGNEDh(30) + PPC64_CLV_UNALIGNEDh(31) + +#endif +#endif + +Lnovec: + ld 0, PPC64_OFFS_CR(3) + mtcr 0 + ld 0, PPC64_OFFS_SRR0(3) + mtctr 0 + + PPC64_LR(0) + PPC64_LR(5) + PPC64_LR(4) + PPC64_LR(1) + PPC64_LR(3) + bctr + +#elif defined(__ppc__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) +// +// void libunwind::Registers_ppc::jumpto() +// +// On entry: +// thread_state pointer is in r3 +// + + // restore integral registerrs + // skip r0 for now + // skip r1 for now + lwz 2, 16(3) + // skip r3 for now + // skip r4 for now + // skip r5 for now + lwz 6, 32(3) + lwz 7, 36(3) + lwz 8, 40(3) + lwz 9, 44(3) + lwz 10, 48(3) + lwz 11, 52(3) + lwz 12, 56(3) + lwz 13, 60(3) + lwz 14, 64(3) + lwz 15, 68(3) + lwz 16, 72(3) + lwz 17, 76(3) + lwz 18, 80(3) + lwz 19, 84(3) + lwz 20, 88(3) + lwz 21, 92(3) + lwz 22, 96(3) + lwz 23,100(3) + lwz 24,104(3) + lwz 25,108(3) + lwz 26,112(3) + lwz 27,116(3) + lwz 28,120(3) + lwz 29,124(3) + lwz 30,128(3) + lwz 31,132(3) + +#ifndef __NO_FPRS__ + // restore float registers + lfd 0, 160(3) + lfd 1, 168(3) + lfd 2, 176(3) + lfd 3, 184(3) + lfd 4, 192(3) + lfd 5, 200(3) + lfd 6, 208(3) + lfd 7, 216(3) + lfd 8, 224(3) + lfd 9, 232(3) + lfd 10,240(3) + lfd 11,248(3) + lfd 12,256(3) + lfd 13,264(3) + lfd 14,272(3) + lfd 15,280(3) + lfd 16,288(3) + lfd 17,296(3) + lfd 18,304(3) + lfd 19,312(3) + lfd 20,320(3) + lfd 21,328(3) + lfd 22,336(3) + lfd 23,344(3) + lfd 24,352(3) + lfd 25,360(3) + lfd 26,368(3) + lfd 27,376(3) + lfd 28,384(3) + lfd 29,392(3) + lfd 30,400(3) + lfd 31,408(3) +#endif + +#if defined(__ALTIVEC__) + // restore vector registers if any are in use + lwz 5, 156(3) // test VRsave + cmpwi 5, 0 + beq Lnovec + + subi 4, 1, 16 + rlwinm 4, 4, 0, 0, 27 // mask low 4-bits + // r4 is now a 16-byte aligned pointer into the red zone + // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer + + +#define LOAD_VECTOR_UNALIGNEDl(_index) \ + andis. 0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + lwz 0, 424+_index*16(3) SEPARATOR \ + stw 0, 0(%r4) SEPARATOR \ + lwz 0, 424+_index*16+4(%r3) SEPARATOR \ + stw 0, 4(%r4) SEPARATOR \ + lwz 0, 424+_index*16+8(%r3) SEPARATOR \ + stw 0, 8(%r4) SEPARATOR \ + lwz 0, 424+_index*16+12(%r3) SEPARATOR \ + stw 0, 12(%r4) SEPARATOR \ + lvx _index, 0, 4 SEPARATOR \ + Ldone ## _index: + +#define LOAD_VECTOR_UNALIGNEDh(_index) \ + andi. 0, 5, (1 PPC_LEFT_SHIFT(31-_index)) SEPARATOR \ + beq Ldone ## _index SEPARATOR \ + lwz 0, 424+_index*16(3) SEPARATOR \ + stw 0, 0(4) SEPARATOR \ + lwz 0, 424+_index*16+4(3) SEPARATOR \ + stw 0, 4(4) SEPARATOR \ + lwz 0, 424+_index*16+8(3) SEPARATOR \ + stw 0, 8(%r4) SEPARATOR \ + lwz 0, 424+_index*16+12(3) SEPARATOR \ + stw 0, 12(4) SEPARATOR \ + lvx _index, 0, 4 SEPARATOR \ + Ldone ## _index: + + + LOAD_VECTOR_UNALIGNEDl(0) + LOAD_VECTOR_UNALIGNEDl(1) + LOAD_VECTOR_UNALIGNEDl(2) + LOAD_VECTOR_UNALIGNEDl(3) + LOAD_VECTOR_UNALIGNEDl(4) + LOAD_VECTOR_UNALIGNEDl(5) + LOAD_VECTOR_UNALIGNEDl(6) + LOAD_VECTOR_UNALIGNEDl(7) + LOAD_VECTOR_UNALIGNEDl(8) + LOAD_VECTOR_UNALIGNEDl(9) + LOAD_VECTOR_UNALIGNEDl(10) + LOAD_VECTOR_UNALIGNEDl(11) + LOAD_VECTOR_UNALIGNEDl(12) + LOAD_VECTOR_UNALIGNEDl(13) + LOAD_VECTOR_UNALIGNEDl(14) + LOAD_VECTOR_UNALIGNEDl(15) + LOAD_VECTOR_UNALIGNEDh(16) + LOAD_VECTOR_UNALIGNEDh(17) + LOAD_VECTOR_UNALIGNEDh(18) + LOAD_VECTOR_UNALIGNEDh(19) + LOAD_VECTOR_UNALIGNEDh(20) + LOAD_VECTOR_UNALIGNEDh(21) + LOAD_VECTOR_UNALIGNEDh(22) + LOAD_VECTOR_UNALIGNEDh(23) + LOAD_VECTOR_UNALIGNEDh(24) + LOAD_VECTOR_UNALIGNEDh(25) + LOAD_VECTOR_UNALIGNEDh(26) + LOAD_VECTOR_UNALIGNEDh(27) + LOAD_VECTOR_UNALIGNEDh(28) + LOAD_VECTOR_UNALIGNEDh(29) + LOAD_VECTOR_UNALIGNEDh(30) + LOAD_VECTOR_UNALIGNEDh(31) +#endif + +Lnovec: + lwz 0, 136(3) // __cr + mtcr 0 + lwz 0, 148(3) // __ctr + mtctr 0 + lwz 0, 0(3) // __ssr0 + mtctr 0 + lwz 0, 8(3) // do r0 now + lwz 5, 28(3) // do r5 now + lwz 4, 24(3) // do r4 now + lwz 1, 12(3) // do sp now + lwz 3, 20(3) // do r3 last + bctr + +#elif defined(__aarch64__) + +// +// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); +// +// On entry: +// thread_state pointer is in x0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto) + // skip restore of x0,x1 for now + ldp x2, x3, [x0, #0x010] + ldp x4, x5, [x0, #0x020] + ldp x6, x7, [x0, #0x030] + ldp x8, x9, [x0, #0x040] + ldp x10,x11, [x0, #0x050] + ldp x12,x13, [x0, #0x060] + ldp x14,x15, [x0, #0x070] + // x16 and x17 were clobbered by the call into the unwinder, so no point in + // restoring them. + ldp x18,x19, [x0, #0x090] + ldp x20,x21, [x0, #0x0A0] + ldp x22,x23, [x0, #0x0B0] + ldp x24,x25, [x0, #0x0C0] + ldp x26,x27, [x0, #0x0D0] + ldp x28,x29, [x0, #0x0E0] + ldr x30, [x0, #0x100] // restore pc into lr + + ldp d0, d1, [x0, #0x110] + ldp d2, d3, [x0, #0x120] + ldp d4, d5, [x0, #0x130] + ldp d6, d7, [x0, #0x140] + ldp d8, d9, [x0, #0x150] + ldp d10,d11, [x0, #0x160] + ldp d12,d13, [x0, #0x170] + ldp d14,d15, [x0, #0x180] + ldp d16,d17, [x0, #0x190] + ldp d18,d19, [x0, #0x1A0] + ldp d20,d21, [x0, #0x1B0] + ldp d22,d23, [x0, #0x1C0] + ldp d24,d25, [x0, #0x1D0] + ldp d26,d27, [x0, #0x1E0] + ldp d28,d29, [x0, #0x1F0] + ldr d30, [x0, #0x200] + ldr d31, [x0, #0x208] + + // Finally, restore sp. This must be done after the the last read from the + // context struct, because it is allocated on the stack, and an exception + // could clobber the de-allocated portion of the stack after sp has been + // restored. + ldr x16, [x0, #0x0F8] + ldp x0, x1, [x0, #0x000] // restore x0,x1 + mov sp,x16 // restore sp + ret x30 // jump to pc + +#elif defined(__arm__) && !defined(__APPLE__) + +#if !defined(__ARM_ARCH_ISA_ARM) +#if (__ARM_ARCH_ISA_THUMB == 2) + .syntax unified +#endif + .thumb +#endif + +@ +@ void libunwind::Registers_arm::restoreCoreAndJumpTo() +@ +@ On entry: +@ thread_state pointer is in r0 +@ + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv) +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + @ r8-r11: ldm into r1-r4, then mov to r8-r11 + adds r0, #0x20 + ldm r0!, {r1-r4} + subs r0, #0x30 + mov r8, r1 + mov r9, r2 + mov r10, r3 + mov r11, r4 + @ r12 does not need loading, it it the intra-procedure-call scratch register + ldr r2, [r0, #0x34] + ldr r3, [r0, #0x3c] + mov sp, r2 + mov lr, r3 @ restore pc into lr + ldm r0, {r0-r7} +#else + @ Use lr as base so that r0 can be restored. + mov lr, r0 + @ 32bit thumb-2 restrictions for ldm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction + ldm lr, {r0-r12} + ldr sp, [lr, #52] + ldr lr, [lr, #60] @ restore pc into lr +#endif + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPv) + @ VFP and iwMMX instructions are only available when compiling with the flags + @ that enable them. We do not want to do that in the library (because we do not + @ want the compiler to generate instructions that access those) but this is + @ only accessed if the personality routine needs these registers. Use of + @ these registers implies they are, actually, available on the target, so + @ it's ok to execute. + @ So, generate the instruction using the corresponding coprocessor mnemonic. + vldmia r0, {d0-d15} + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPv) + vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPv) + vldmia r0, {d16-d31} + JMP(lr) + +#if defined(__ARM_WMMX) + +@ +@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPv) + ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8 + ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8 + ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8 + ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8 + ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8 + ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8 + ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8 + ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8 + ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8 + ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8 + ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8 + ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8 + ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8 + ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8 + ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8 + ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8 + JMP(lr) + +@ +@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj) + ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4 + ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4 + ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4 + ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4 + JMP(lr) + +#endif + +#elif defined(__or1k__) + +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) +# +# void libunwind::Registers_or1k::jumpto() +# +# On entry: +# thread_state pointer is in r3 +# + + # restore integral registers + l.lwz r0, 0(r3) + l.lwz r1, 4(r3) + l.lwz r2, 8(r3) + # skip r3 for now + l.lwz r4, 16(r3) + l.lwz r5, 20(r3) + l.lwz r6, 24(r3) + l.lwz r7, 28(r3) + l.lwz r8, 32(r3) + # skip r9 + l.lwz r10, 40(r3) + l.lwz r11, 44(r3) + l.lwz r12, 48(r3) + l.lwz r13, 52(r3) + l.lwz r14, 56(r3) + l.lwz r15, 60(r3) + l.lwz r16, 64(r3) + l.lwz r17, 68(r3) + l.lwz r18, 72(r3) + l.lwz r19, 76(r3) + l.lwz r20, 80(r3) + l.lwz r21, 84(r3) + l.lwz r22, 88(r3) + l.lwz r23, 92(r3) + l.lwz r24, 96(r3) + l.lwz r25,100(r3) + l.lwz r26,104(r3) + l.lwz r27,108(r3) + l.lwz r28,112(r3) + l.lwz r29,116(r3) + l.lwz r30,120(r3) + l.lwz r31,124(r3) + + # load new pc into ra + l.lwz r9, 128(r3) + + # at last, restore r3 + l.lwz r3, 12(r3) + + # jump to pc + l.jr r9 + l.nop + +#elif defined(__hexagon__) +# On entry: +# thread_state pointer is in r2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv) +# +# void libunwind::Registers_hexagon::jumpto() +# + r8 = memw(r0+#32) + r9 = memw(r0+#36) + r10 = memw(r0+#40) + r11 = memw(r0+#44) + + r12 = memw(r0+#48) + r13 = memw(r0+#52) + r14 = memw(r0+#56) + r15 = memw(r0+#60) + + r16 = memw(r0+#64) + r17 = memw(r0+#68) + r18 = memw(r0+#72) + r19 = memw(r0+#76) + + r20 = memw(r0+#80) + r21 = memw(r0+#84) + r22 = memw(r0+#88) + r23 = memw(r0+#92) + + r24 = memw(r0+#96) + r25 = memw(r0+#100) + r26 = memw(r0+#104) + r27 = memw(r0+#108) + + r28 = memw(r0+#112) + r29 = memw(r0+#116) + r30 = memw(r0+#120) + r31 = memw(r0+#132) + + r1 = memw(r0+#128) + c4 = r1 // Predicate register + r1 = memw(r0+#4) + r0 = memw(r0) + jumpr r31 +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +// +// void libunwind::Registers_mips_o32::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float +#if __mips_fpr != 64 + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) +#else + ldc1 $f0, (4 * 36 + 8 * 0)($4) + ldc1 $f1, (4 * 36 + 8 * 1)($4) + ldc1 $f2, (4 * 36 + 8 * 2)($4) + ldc1 $f3, (4 * 36 + 8 * 3)($4) + ldc1 $f4, (4 * 36 + 8 * 4)($4) + ldc1 $f5, (4 * 36 + 8 * 5)($4) + ldc1 $f6, (4 * 36 + 8 * 6)($4) + ldc1 $f7, (4 * 36 + 8 * 7)($4) + ldc1 $f8, (4 * 36 + 8 * 8)($4) + ldc1 $f9, (4 * 36 + 8 * 9)($4) + ldc1 $f10, (4 * 36 + 8 * 10)($4) + ldc1 $f11, (4 * 36 + 8 * 11)($4) + ldc1 $f12, (4 * 36 + 8 * 12)($4) + ldc1 $f13, (4 * 36 + 8 * 13)($4) + ldc1 $f14, (4 * 36 + 8 * 14)($4) + ldc1 $f15, (4 * 36 + 8 * 15)($4) + ldc1 $f16, (4 * 36 + 8 * 16)($4) + ldc1 $f17, (4 * 36 + 8 * 17)($4) + ldc1 $f18, (4 * 36 + 8 * 18)($4) + ldc1 $f19, (4 * 36 + 8 * 19)($4) + ldc1 $f20, (4 * 36 + 8 * 20)($4) + ldc1 $f21, (4 * 36 + 8 * 21)($4) + ldc1 $f22, (4 * 36 + 8 * 22)($4) + ldc1 $f23, (4 * 36 + 8 * 23)($4) + ldc1 $f24, (4 * 36 + 8 * 24)($4) + ldc1 $f25, (4 * 36 + 8 * 25)($4) + ldc1 $f26, (4 * 36 + 8 * 26)($4) + ldc1 $f27, (4 * 36 + 8 * 27)($4) + ldc1 $f28, (4 * 36 + 8 * 28)($4) + ldc1 $f29, (4 * 36 + 8 * 29)($4) + ldc1 $f30, (4 * 36 + 8 * 30)($4) + ldc1 $f31, (4 * 36 + 8 * 31)($4) +#endif +#endif + // restore hi and lo + lw $8, (4 * 33)($4) + mthi $8 + lw $8, (4 * 34)($4) + mtlo $8 + // r0 is zero + lw $1, (4 * 1)($4) + lw $2, (4 * 2)($4) + lw $3, (4 * 3)($4) + // skip a0 for now + lw $5, (4 * 5)($4) + lw $6, (4 * 6)($4) + lw $7, (4 * 7)($4) + lw $8, (4 * 8)($4) + lw $9, (4 * 9)($4) + lw $10, (4 * 10)($4) + lw $11, (4 * 11)($4) + lw $12, (4 * 12)($4) + lw $13, (4 * 13)($4) + lw $14, (4 * 14)($4) + lw $15, (4 * 15)($4) + lw $16, (4 * 16)($4) + lw $17, (4 * 17)($4) + lw $18, (4 * 18)($4) + lw $19, (4 * 19)($4) + lw $20, (4 * 20)($4) + lw $21, (4 * 21)($4) + lw $22, (4 * 22)($4) + lw $23, (4 * 23)($4) + lw $24, (4 * 24)($4) + lw $25, (4 * 25)($4) + lw $26, (4 * 26)($4) + lw $27, (4 * 27)($4) + lw $28, (4 * 28)($4) + lw $29, (4 * 29)($4) + lw $30, (4 * 30)($4) + // load new pc into ra + lw $31, (4 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + lw $4, (4 * 4)($4) + .set pop + +#elif defined(__mips64) + +// +// void libunwind::Registers_mips_newabi::jumpto() +// +// On entry: +// thread state pointer is in a0 ($4) +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv) + .set push + .set noat + .set noreorder + .set nomacro +#ifdef __mips_hard_float + ldc1 $f0, (8 * 35)($4) + ldc1 $f1, (8 * 36)($4) + ldc1 $f2, (8 * 37)($4) + ldc1 $f3, (8 * 38)($4) + ldc1 $f4, (8 * 39)($4) + ldc1 $f5, (8 * 40)($4) + ldc1 $f6, (8 * 41)($4) + ldc1 $f7, (8 * 42)($4) + ldc1 $f8, (8 * 43)($4) + ldc1 $f9, (8 * 44)($4) + ldc1 $f10, (8 * 45)($4) + ldc1 $f11, (8 * 46)($4) + ldc1 $f12, (8 * 47)($4) + ldc1 $f13, (8 * 48)($4) + ldc1 $f14, (8 * 49)($4) + ldc1 $f15, (8 * 50)($4) + ldc1 $f16, (8 * 51)($4) + ldc1 $f17, (8 * 52)($4) + ldc1 $f18, (8 * 53)($4) + ldc1 $f19, (8 * 54)($4) + ldc1 $f20, (8 * 55)($4) + ldc1 $f21, (8 * 56)($4) + ldc1 $f22, (8 * 57)($4) + ldc1 $f23, (8 * 58)($4) + ldc1 $f24, (8 * 59)($4) + ldc1 $f25, (8 * 60)($4) + ldc1 $f26, (8 * 61)($4) + ldc1 $f27, (8 * 62)($4) + ldc1 $f28, (8 * 63)($4) + ldc1 $f29, (8 * 64)($4) + ldc1 $f30, (8 * 65)($4) + ldc1 $f31, (8 * 66)($4) +#endif + // restore hi and lo + ld $8, (8 * 33)($4) + mthi $8 + ld $8, (8 * 34)($4) + mtlo $8 + // r0 is zero + ld $1, (8 * 1)($4) + ld $2, (8 * 2)($4) + ld $3, (8 * 3)($4) + // skip a0 for now + ld $5, (8 * 5)($4) + ld $6, (8 * 6)($4) + ld $7, (8 * 7)($4) + ld $8, (8 * 8)($4) + ld $9, (8 * 9)($4) + ld $10, (8 * 10)($4) + ld $11, (8 * 11)($4) + ld $12, (8 * 12)($4) + ld $13, (8 * 13)($4) + ld $14, (8 * 14)($4) + ld $15, (8 * 15)($4) + ld $16, (8 * 16)($4) + ld $17, (8 * 17)($4) + ld $18, (8 * 18)($4) + ld $19, (8 * 19)($4) + ld $20, (8 * 20)($4) + ld $21, (8 * 21)($4) + ld $22, (8 * 22)($4) + ld $23, (8 * 23)($4) + ld $24, (8 * 24)($4) + ld $25, (8 * 25)($4) + ld $26, (8 * 26)($4) + ld $27, (8 * 27)($4) + ld $28, (8 * 28)($4) + ld $29, (8 * 29)($4) + ld $30, (8 * 30)($4) + // load new pc into ra + ld $31, (8 * 32)($4) + // jump to ra, load a0 in the delay slot + jr $31 + ld $4, (8 * 4)($4) + .set pop + +#elif defined(__sparc__) + +// +// void libunwind::Registers_sparc_o32::jumpto() +// +// On entry: +// thread_state pointer is in o0 +// +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv) + ta 3 + ldd [%o0 + 64], %l0 + ldd [%o0 + 72], %l2 + ldd [%o0 + 80], %l4 + ldd [%o0 + 88], %l6 + ldd [%o0 + 96], %i0 + ldd [%o0 + 104], %i2 + ldd [%o0 + 112], %i4 + ldd [%o0 + 120], %i6 + ld [%o0 + 60], %o7 + jmp %o7 + nop + +#elif defined(__riscv) + +// +// void libunwind::Registers_riscv::jumpto() +// +// On entry: +// thread_state pointer is in a0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv) +# if defined(__riscv_flen) + FLOAD f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0) + FLOAD f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0) + FLOAD f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0) + FLOAD f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0) + FLOAD f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0) + FLOAD f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0) + FLOAD f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0) + FLOAD f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0) + FLOAD f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0) + FLOAD f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0) + FLOAD f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0) + FLOAD f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0) + FLOAD f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0) + FLOAD f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0) + FLOAD f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0) + FLOAD f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0) + FLOAD f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0) + FLOAD f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0) + FLOAD f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0) + FLOAD f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0) + FLOAD f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0) + FLOAD f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0) + FLOAD f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0) + FLOAD f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0) + FLOAD f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0) + FLOAD f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0) + FLOAD f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0) + FLOAD f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0) + FLOAD f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0) + FLOAD f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0) + FLOAD f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0) + FLOAD f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0) +# endif + + // x0 is zero + ILOAD x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra + ILOAD x2, (RISCV_ISIZE * 2)(a0) + ILOAD x3, (RISCV_ISIZE * 3)(a0) + ILOAD x4, (RISCV_ISIZE * 4)(a0) + ILOAD x5, (RISCV_ISIZE * 5)(a0) + ILOAD x6, (RISCV_ISIZE * 6)(a0) + ILOAD x7, (RISCV_ISIZE * 7)(a0) + ILOAD x8, (RISCV_ISIZE * 8)(a0) + ILOAD x9, (RISCV_ISIZE * 9)(a0) + // skip a0 for now + ILOAD x11, (RISCV_ISIZE * 11)(a0) + ILOAD x12, (RISCV_ISIZE * 12)(a0) + ILOAD x13, (RISCV_ISIZE * 13)(a0) + ILOAD x14, (RISCV_ISIZE * 14)(a0) + ILOAD x15, (RISCV_ISIZE * 15)(a0) + ILOAD x16, (RISCV_ISIZE * 16)(a0) + ILOAD x17, (RISCV_ISIZE * 17)(a0) + ILOAD x18, (RISCV_ISIZE * 18)(a0) + ILOAD x19, (RISCV_ISIZE * 19)(a0) + ILOAD x20, (RISCV_ISIZE * 20)(a0) + ILOAD x21, (RISCV_ISIZE * 21)(a0) + ILOAD x22, (RISCV_ISIZE * 22)(a0) + ILOAD x23, (RISCV_ISIZE * 23)(a0) + ILOAD x24, (RISCV_ISIZE * 24)(a0) + ILOAD x25, (RISCV_ISIZE * 25)(a0) + ILOAD x26, (RISCV_ISIZE * 26)(a0) + ILOAD x27, (RISCV_ISIZE * 27)(a0) + ILOAD x28, (RISCV_ISIZE * 28)(a0) + ILOAD x29, (RISCV_ISIZE * 29)(a0) + ILOAD x30, (RISCV_ISIZE * 30)(a0) + ILOAD x31, (RISCV_ISIZE * 31)(a0) + ILOAD x10, (RISCV_ISIZE * 10)(a0) // restore a0 + + ret // jump to ra + +#endif + +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE + diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S new file mode 100644 index 0000000000..e565c8ffcb --- /dev/null +++ b/libunwind/src/UnwindRegistersSave.S @@ -0,0 +1,1117 @@ +//===------------------------ UnwindRegistersSave.S -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "assembly.h" + + .text + +#if !defined(__USING_SJLJ_EXCEPTIONS__) + +#if defined(__i386__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + + _LIBUNWIND_CET_ENDBR + push %eax + movl 8(%esp), %eax + movl %ebx, 4(%eax) + movl %ecx, 8(%eax) + movl %edx, 12(%eax) + movl %edi, 16(%eax) + movl %esi, 20(%eax) + movl %ebp, 24(%eax) + movl %esp, %edx + addl $8, %edx + movl %edx, 28(%eax) # store what sp was at call site as esp + # skip ss + # skip eflags + movl 4(%esp), %edx + movl %edx, 40(%eax) # store return address as eip + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + movl (%esp), %edx + movl %edx, (%eax) # store original eax + popl %eax + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif defined(__x86_64__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in rdi +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) +#if defined(_WIN64) +#define PTR %rcx +#define TMP %rdx +#else +#define PTR %rdi +#define TMP %rsi +#endif + + _LIBUNWIND_CET_ENDBR + movq %rax, (PTR) + movq %rbx, 8(PTR) + movq %rcx, 16(PTR) + movq %rdx, 24(PTR) + movq %rdi, 32(PTR) + movq %rsi, 40(PTR) + movq %rbp, 48(PTR) + movq %rsp, 56(PTR) + addq $8, 56(PTR) + movq %r8, 64(PTR) + movq %r9, 72(PTR) + movq %r10, 80(PTR) + movq %r11, 88(PTR) + movq %r12, 96(PTR) + movq %r13,104(PTR) + movq %r14,112(PTR) + movq %r15,120(PTR) + movq (%rsp),TMP + movq TMP,128(PTR) # store return address as rip + # skip rflags + # skip cs + # skip fs + # skip gs + +#if defined(_WIN64) + movdqu %xmm0,176(PTR) + movdqu %xmm1,192(PTR) + movdqu %xmm2,208(PTR) + movdqu %xmm3,224(PTR) + movdqu %xmm4,240(PTR) + movdqu %xmm5,256(PTR) + movdqu %xmm6,272(PTR) + movdqu %xmm7,288(PTR) + movdqu %xmm8,304(PTR) + movdqu %xmm9,320(PTR) + movdqu %xmm10,336(PTR) + movdqu %xmm11,352(PTR) + movdqu %xmm12,368(PTR) + movdqu %xmm13,384(PTR) + movdqu %xmm14,400(PTR) + movdqu %xmm15,416(PTR) +#endif + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sw $1, (4 * 1)($4) + sw $2, (4 * 2)($4) + sw $3, (4 * 3)($4) + sw $4, (4 * 4)($4) + sw $5, (4 * 5)($4) + sw $6, (4 * 6)($4) + sw $7, (4 * 7)($4) + sw $8, (4 * 8)($4) + sw $9, (4 * 9)($4) + sw $10, (4 * 10)($4) + sw $11, (4 * 11)($4) + sw $12, (4 * 12)($4) + sw $13, (4 * 13)($4) + sw $14, (4 * 14)($4) + sw $15, (4 * 15)($4) + sw $16, (4 * 16)($4) + sw $17, (4 * 17)($4) + sw $18, (4 * 18)($4) + sw $19, (4 * 19)($4) + sw $20, (4 * 20)($4) + sw $21, (4 * 21)($4) + sw $22, (4 * 22)($4) + sw $23, (4 * 23)($4) + sw $24, (4 * 24)($4) + sw $25, (4 * 25)($4) + sw $26, (4 * 26)($4) + sw $27, (4 * 27)($4) + sw $28, (4 * 28)($4) + sw $29, (4 * 29)($4) + sw $30, (4 * 30)($4) + sw $31, (4 * 31)($4) + # Store return address to pc + sw $31, (4 * 32)($4) + # hi and lo + mfhi $8 + sw $8, (4 * 33)($4) + mflo $8 + sw $8, (4 * 34)($4) +#ifdef __mips_hard_float +#if __mips_fpr != 64 + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) +#else + sdc1 $f0, (4 * 36 + 8 * 0)($4) + sdc1 $f1, (4 * 36 + 8 * 1)($4) + sdc1 $f2, (4 * 36 + 8 * 2)($4) + sdc1 $f3, (4 * 36 + 8 * 3)($4) + sdc1 $f4, (4 * 36 + 8 * 4)($4) + sdc1 $f5, (4 * 36 + 8 * 5)($4) + sdc1 $f6, (4 * 36 + 8 * 6)($4) + sdc1 $f7, (4 * 36 + 8 * 7)($4) + sdc1 $f8, (4 * 36 + 8 * 8)($4) + sdc1 $f9, (4 * 36 + 8 * 9)($4) + sdc1 $f10, (4 * 36 + 8 * 10)($4) + sdc1 $f11, (4 * 36 + 8 * 11)($4) + sdc1 $f12, (4 * 36 + 8 * 12)($4) + sdc1 $f13, (4 * 36 + 8 * 13)($4) + sdc1 $f14, (4 * 36 + 8 * 14)($4) + sdc1 $f15, (4 * 36 + 8 * 15)($4) + sdc1 $f16, (4 * 36 + 8 * 16)($4) + sdc1 $f17, (4 * 36 + 8 * 17)($4) + sdc1 $f18, (4 * 36 + 8 * 18)($4) + sdc1 $f19, (4 * 36 + 8 * 19)($4) + sdc1 $f20, (4 * 36 + 8 * 20)($4) + sdc1 $f21, (4 * 36 + 8 * 21)($4) + sdc1 $f22, (4 * 36 + 8 * 22)($4) + sdc1 $f23, (4 * 36 + 8 * 23)($4) + sdc1 $f24, (4 * 36 + 8 * 24)($4) + sdc1 $f25, (4 * 36 + 8 * 25)($4) + sdc1 $f26, (4 * 36 + 8 * 26)($4) + sdc1 $f27, (4 * 36 + 8 * 27)($4) + sdc1 $f28, (4 * 36 + 8 * 28)($4) + sdc1 $f29, (4 * 36 + 8 * 29)($4) + sdc1 $f30, (4 * 36 + 8 * 30)($4) + sdc1 $f31, (4 * 36 + 8 * 31)($4) +#endif +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + +#elif defined(__mips64) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 ($4) +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + .set push + .set noat + .set noreorder + .set nomacro + sd $1, (8 * 1)($4) + sd $2, (8 * 2)($4) + sd $3, (8 * 3)($4) + sd $4, (8 * 4)($4) + sd $5, (8 * 5)($4) + sd $6, (8 * 6)($4) + sd $7, (8 * 7)($4) + sd $8, (8 * 8)($4) + sd $9, (8 * 9)($4) + sd $10, (8 * 10)($4) + sd $11, (8 * 11)($4) + sd $12, (8 * 12)($4) + sd $13, (8 * 13)($4) + sd $14, (8 * 14)($4) + sd $15, (8 * 15)($4) + sd $16, (8 * 16)($4) + sd $17, (8 * 17)($4) + sd $18, (8 * 18)($4) + sd $19, (8 * 19)($4) + sd $20, (8 * 20)($4) + sd $21, (8 * 21)($4) + sd $22, (8 * 22)($4) + sd $23, (8 * 23)($4) + sd $24, (8 * 24)($4) + sd $25, (8 * 25)($4) + sd $26, (8 * 26)($4) + sd $27, (8 * 27)($4) + sd $28, (8 * 28)($4) + sd $29, (8 * 29)($4) + sd $30, (8 * 30)($4) + sd $31, (8 * 31)($4) + # Store return address to pc + sd $31, (8 * 32)($4) + # hi and lo + mfhi $8 + sd $8, (8 * 33)($4) + mflo $8 + sd $8, (8 * 34)($4) +#ifdef __mips_hard_float + sdc1 $f0, (8 * 35)($4) + sdc1 $f1, (8 * 36)($4) + sdc1 $f2, (8 * 37)($4) + sdc1 $f3, (8 * 38)($4) + sdc1 $f4, (8 * 39)($4) + sdc1 $f5, (8 * 40)($4) + sdc1 $f6, (8 * 41)($4) + sdc1 $f7, (8 * 42)($4) + sdc1 $f8, (8 * 43)($4) + sdc1 $f9, (8 * 44)($4) + sdc1 $f10, (8 * 45)($4) + sdc1 $f11, (8 * 46)($4) + sdc1 $f12, (8 * 47)($4) + sdc1 $f13, (8 * 48)($4) + sdc1 $f14, (8 * 49)($4) + sdc1 $f15, (8 * 50)($4) + sdc1 $f16, (8 * 51)($4) + sdc1 $f17, (8 * 52)($4) + sdc1 $f18, (8 * 53)($4) + sdc1 $f19, (8 * 54)($4) + sdc1 $f20, (8 * 55)($4) + sdc1 $f21, (8 * 56)($4) + sdc1 $f22, (8 * 57)($4) + sdc1 $f23, (8 * 58)($4) + sdc1 $f24, (8 * 59)($4) + sdc1 $f25, (8 * 60)($4) + sdc1 $f26, (8 * 61)($4) + sdc1 $f27, (8 * 62)($4) + sdc1 $f28, (8 * 63)($4) + sdc1 $f29, (8 * 64)($4) + sdc1 $f30, (8 * 65)($4) + sdc1 $f31, (8 * 66)($4) +#endif + jr $31 + # return UNW_ESUCCESS + or $2, $0, $0 + .set pop + +# elif defined(__mips__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# Just trap for the time being. +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + teq $0, $0 + +#elif defined(__powerpc64__) + +// +// extern int __unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + +// store register (GPR) +#define PPC64_STR(n) \ + std n, (8 * (n + 2))(3) + + // save GPRs + PPC64_STR(0) + mflr 0 + std 0, PPC64_OFFS_SRR0(3) // store lr as ssr0 + PPC64_STR(1) + PPC64_STR(2) + PPC64_STR(3) + PPC64_STR(4) + PPC64_STR(5) + PPC64_STR(6) + PPC64_STR(7) + PPC64_STR(8) + PPC64_STR(9) + PPC64_STR(10) + PPC64_STR(11) + PPC64_STR(12) + PPC64_STR(13) + PPC64_STR(14) + PPC64_STR(15) + PPC64_STR(16) + PPC64_STR(17) + PPC64_STR(18) + PPC64_STR(19) + PPC64_STR(20) + PPC64_STR(21) + PPC64_STR(22) + PPC64_STR(23) + PPC64_STR(24) + PPC64_STR(25) + PPC64_STR(26) + PPC64_STR(27) + PPC64_STR(28) + PPC64_STR(29) + PPC64_STR(30) + PPC64_STR(31) + + mfcr 0 + std 0, PPC64_OFFS_CR(3) + mfxer 0 + std 0, PPC64_OFFS_XER(3) + mflr 0 + std 0, PPC64_OFFS_LR(3) + mfctr 0 + std 0, PPC64_OFFS_CTR(3) + mfvrsave 0 + std 0, PPC64_OFFS_VRSAVE(3) + +#if defined(__VSX__) + // save VS registers + // (note that this also saves floating point registers and V registers, + // because part of VS is mapped to these registers) + + addi 4, 3, PPC64_OFFS_FP + +// store VS register +#define PPC64_STVS(n) \ + stxvd2x n, 0, 4 ;\ + addi 4, 4, 16 + + PPC64_STVS(0) + PPC64_STVS(1) + PPC64_STVS(2) + PPC64_STVS(3) + PPC64_STVS(4) + PPC64_STVS(5) + PPC64_STVS(6) + PPC64_STVS(7) + PPC64_STVS(8) + PPC64_STVS(9) + PPC64_STVS(10) + PPC64_STVS(11) + PPC64_STVS(12) + PPC64_STVS(13) + PPC64_STVS(14) + PPC64_STVS(15) + PPC64_STVS(16) + PPC64_STVS(17) + PPC64_STVS(18) + PPC64_STVS(19) + PPC64_STVS(20) + PPC64_STVS(21) + PPC64_STVS(22) + PPC64_STVS(23) + PPC64_STVS(24) + PPC64_STVS(25) + PPC64_STVS(26) + PPC64_STVS(27) + PPC64_STVS(28) + PPC64_STVS(29) + PPC64_STVS(30) + PPC64_STVS(31) + PPC64_STVS(32) + PPC64_STVS(33) + PPC64_STVS(34) + PPC64_STVS(35) + PPC64_STVS(36) + PPC64_STVS(37) + PPC64_STVS(38) + PPC64_STVS(39) + PPC64_STVS(40) + PPC64_STVS(41) + PPC64_STVS(42) + PPC64_STVS(43) + PPC64_STVS(44) + PPC64_STVS(45) + PPC64_STVS(46) + PPC64_STVS(47) + PPC64_STVS(48) + PPC64_STVS(49) + PPC64_STVS(50) + PPC64_STVS(51) + PPC64_STVS(52) + PPC64_STVS(53) + PPC64_STVS(54) + PPC64_STVS(55) + PPC64_STVS(56) + PPC64_STVS(57) + PPC64_STVS(58) + PPC64_STVS(59) + PPC64_STVS(60) + PPC64_STVS(61) + PPC64_STVS(62) + PPC64_STVS(63) + +#else + +// store FP register +#define PPC64_STF(n) \ + stfd n, (PPC64_OFFS_FP + n * 16)(3) + + // save float registers + PPC64_STF(0) + PPC64_STF(1) + PPC64_STF(2) + PPC64_STF(3) + PPC64_STF(4) + PPC64_STF(5) + PPC64_STF(6) + PPC64_STF(7) + PPC64_STF(8) + PPC64_STF(9) + PPC64_STF(10) + PPC64_STF(11) + PPC64_STF(12) + PPC64_STF(13) + PPC64_STF(14) + PPC64_STF(15) + PPC64_STF(16) + PPC64_STF(17) + PPC64_STF(18) + PPC64_STF(19) + PPC64_STF(20) + PPC64_STF(21) + PPC64_STF(22) + PPC64_STF(23) + PPC64_STF(24) + PPC64_STF(25) + PPC64_STF(26) + PPC64_STF(27) + PPC64_STF(28) + PPC64_STF(29) + PPC64_STF(30) + PPC64_STF(31) + +#if defined(__ALTIVEC__) + // save vector registers + + // Use 16-bytes below the stack pointer as an + // aligned buffer to save each vector register. + // Note that the stack pointer is always 16-byte aligned. + subi 4, 1, 16 + +#define PPC64_STV_UNALIGNED(n) \ + stvx n, 0, 4 ;\ + ld 5, 0(4) ;\ + std 5, (PPC64_OFFS_V + n * 16)(3) ;\ + ld 5, 8(4) ;\ + std 5, (PPC64_OFFS_V + n * 16 + 8)(3) + + PPC64_STV_UNALIGNED(0) + PPC64_STV_UNALIGNED(1) + PPC64_STV_UNALIGNED(2) + PPC64_STV_UNALIGNED(3) + PPC64_STV_UNALIGNED(4) + PPC64_STV_UNALIGNED(5) + PPC64_STV_UNALIGNED(6) + PPC64_STV_UNALIGNED(7) + PPC64_STV_UNALIGNED(8) + PPC64_STV_UNALIGNED(9) + PPC64_STV_UNALIGNED(10) + PPC64_STV_UNALIGNED(11) + PPC64_STV_UNALIGNED(12) + PPC64_STV_UNALIGNED(13) + PPC64_STV_UNALIGNED(14) + PPC64_STV_UNALIGNED(15) + PPC64_STV_UNALIGNED(16) + PPC64_STV_UNALIGNED(17) + PPC64_STV_UNALIGNED(18) + PPC64_STV_UNALIGNED(19) + PPC64_STV_UNALIGNED(20) + PPC64_STV_UNALIGNED(21) + PPC64_STV_UNALIGNED(22) + PPC64_STV_UNALIGNED(23) + PPC64_STV_UNALIGNED(24) + PPC64_STV_UNALIGNED(25) + PPC64_STV_UNALIGNED(26) + PPC64_STV_UNALIGNED(27) + PPC64_STV_UNALIGNED(28) + PPC64_STV_UNALIGNED(29) + PPC64_STV_UNALIGNED(30) + PPC64_STV_UNALIGNED(31) + +#endif +#endif + + li 3, 0 // return UNW_ESUCCESS + blr + + +#elif defined(__ppc__) + +// +// extern int unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + stw 0, 8(3) + mflr 0 + stw 0, 0(3) // store lr as ssr0 + stw 1, 12(3) + stw 2, 16(3) + stw 3, 20(3) + stw 4, 24(3) + stw 5, 28(3) + stw 6, 32(3) + stw 7, 36(3) + stw 8, 40(3) + stw 9, 44(3) + stw 10, 48(3) + stw 11, 52(3) + stw 12, 56(3) + stw 13, 60(3) + stw 14, 64(3) + stw 15, 68(3) + stw 16, 72(3) + stw 17, 76(3) + stw 18, 80(3) + stw 19, 84(3) + stw 20, 88(3) + stw 21, 92(3) + stw 22, 96(3) + stw 23,100(3) + stw 24,104(3) + stw 25,108(3) + stw 26,112(3) + stw 27,116(3) + stw 28,120(3) + stw 29,124(3) + stw 30,128(3) + stw 31,132(3) + + // save VRSave register + mfspr 0, 256 + stw 0, 156(3) + // save CR registers + mfcr 0 + stw 0, 136(3) + // save CTR register + mfctr 0 + stw 0, 148(3) + +#if !defined(__NO_FPRS__) + // save float registers + stfd 0, 160(3) + stfd 1, 168(3) + stfd 2, 176(3) + stfd 3, 184(3) + stfd 4, 192(3) + stfd 5, 200(3) + stfd 6, 208(3) + stfd 7, 216(3) + stfd 8, 224(3) + stfd 9, 232(3) + stfd 10,240(3) + stfd 11,248(3) + stfd 12,256(3) + stfd 13,264(3) + stfd 14,272(3) + stfd 15,280(3) + stfd 16,288(3) + stfd 17,296(3) + stfd 18,304(3) + stfd 19,312(3) + stfd 20,320(3) + stfd 21,328(3) + stfd 22,336(3) + stfd 23,344(3) + stfd 24,352(3) + stfd 25,360(3) + stfd 26,368(3) + stfd 27,376(3) + stfd 28,384(3) + stfd 29,392(3) + stfd 30,400(3) + stfd 31,408(3) +#endif + +#if defined(__ALTIVEC__) + // save vector registers + + subi 4, 1, 16 + rlwinm 4, 4, 0, 0, 27 // mask low 4-bits + // r4 is now a 16-byte aligned pointer into the red zone + +#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ + stvx _vec, 0, 4 SEPARATOR \ + lwz 5, 0(4) SEPARATOR \ + stw 5, _offset(3) SEPARATOR \ + lwz 5, 4(4) SEPARATOR \ + stw 5, _offset+4(3) SEPARATOR \ + lwz 5, 8(4) SEPARATOR \ + stw 5, _offset+8(3) SEPARATOR \ + lwz 5, 12(4) SEPARATOR \ + stw 5, _offset+12(3) + + SAVE_VECTOR_UNALIGNED( 0, 424+0x000) + SAVE_VECTOR_UNALIGNED( 1, 424+0x010) + SAVE_VECTOR_UNALIGNED( 2, 424+0x020) + SAVE_VECTOR_UNALIGNED( 3, 424+0x030) + SAVE_VECTOR_UNALIGNED( 4, 424+0x040) + SAVE_VECTOR_UNALIGNED( 5, 424+0x050) + SAVE_VECTOR_UNALIGNED( 6, 424+0x060) + SAVE_VECTOR_UNALIGNED( 7, 424+0x070) + SAVE_VECTOR_UNALIGNED( 8, 424+0x080) + SAVE_VECTOR_UNALIGNED( 9, 424+0x090) + SAVE_VECTOR_UNALIGNED(10, 424+0x0A0) + SAVE_VECTOR_UNALIGNED(11, 424+0x0B0) + SAVE_VECTOR_UNALIGNED(12, 424+0x0C0) + SAVE_VECTOR_UNALIGNED(13, 424+0x0D0) + SAVE_VECTOR_UNALIGNED(14, 424+0x0E0) + SAVE_VECTOR_UNALIGNED(15, 424+0x0F0) + SAVE_VECTOR_UNALIGNED(16, 424+0x100) + SAVE_VECTOR_UNALIGNED(17, 424+0x110) + SAVE_VECTOR_UNALIGNED(18, 424+0x120) + SAVE_VECTOR_UNALIGNED(19, 424+0x130) + SAVE_VECTOR_UNALIGNED(20, 424+0x140) + SAVE_VECTOR_UNALIGNED(21, 424+0x150) + SAVE_VECTOR_UNALIGNED(22, 424+0x160) + SAVE_VECTOR_UNALIGNED(23, 424+0x170) + SAVE_VECTOR_UNALIGNED(24, 424+0x180) + SAVE_VECTOR_UNALIGNED(25, 424+0x190) + SAVE_VECTOR_UNALIGNED(26, 424+0x1A0) + SAVE_VECTOR_UNALIGNED(27, 424+0x1B0) + SAVE_VECTOR_UNALIGNED(28, 424+0x1C0) + SAVE_VECTOR_UNALIGNED(29, 424+0x1D0) + SAVE_VECTOR_UNALIGNED(30, 424+0x1E0) + SAVE_VECTOR_UNALIGNED(31, 424+0x1F0) +#endif + + li 3, 0 // return UNW_ESUCCESS + blr + + +#elif defined(__aarch64__) + +// +// extern int __unw_getcontext(unw_context_t* thread_state) +// +// On entry: +// thread_state pointer is in x0 +// + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + stp x0, x1, [x0, #0x000] + stp x2, x3, [x0, #0x010] + stp x4, x5, [x0, #0x020] + stp x6, x7, [x0, #0x030] + stp x8, x9, [x0, #0x040] + stp x10,x11, [x0, #0x050] + stp x12,x13, [x0, #0x060] + stp x14,x15, [x0, #0x070] + stp x16,x17, [x0, #0x080] + stp x18,x19, [x0, #0x090] + stp x20,x21, [x0, #0x0A0] + stp x22,x23, [x0, #0x0B0] + stp x24,x25, [x0, #0x0C0] + stp x26,x27, [x0, #0x0D0] + stp x28,x29, [x0, #0x0E0] + str x30, [x0, #0x0F0] + mov x1,sp + str x1, [x0, #0x0F8] + str x30, [x0, #0x100] // store return address as pc + // skip cpsr + stp d0, d1, [x0, #0x110] + stp d2, d3, [x0, #0x120] + stp d4, d5, [x0, #0x130] + stp d6, d7, [x0, #0x140] + stp d8, d9, [x0, #0x150] + stp d10,d11, [x0, #0x160] + stp d12,d13, [x0, #0x170] + stp d14,d15, [x0, #0x180] + stp d16,d17, [x0, #0x190] + stp d18,d19, [x0, #0x1A0] + stp d20,d21, [x0, #0x1B0] + stp d22,d23, [x0, #0x1C0] + stp d24,d25, [x0, #0x1D0] + stp d26,d27, [x0, #0x1E0] + stp d28,d29, [x0, #0x1F0] + str d30, [x0, #0x200] + str d31, [x0, #0x208] + mov x0, #0 // return UNW_ESUCCESS + ret + +#elif defined(__arm__) && !defined(__APPLE__) + +#if !defined(__ARM_ARCH_ISA_ARM) +#if (__ARM_ARCH_ISA_THUMB == 2) + .syntax unified +#endif + .thumb +#endif + +@ +@ extern int __unw_getcontext(unw_context_t* thread_state) +@ +@ On entry: +@ thread_state pointer is in r0 +@ +@ Per EHABI #4.7 this only saves the core integer registers. +@ EHABI #7.4.5 notes that in general all VRS registers should be restored +@ however this is very hard to do for VFP registers because it is unknown +@ to the library how many registers are implemented by the architecture. +@ Instead, VFP registers are demand saved by logic external to __unw_getcontext. +@ + .p2align 2 +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) +#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1 + stm r0!, {r0-r7} + mov r1, r8 + mov r2, r9 + mov r3, r10 + stm r0!, {r1-r3} + mov r1, r11 + mov r2, sp + mov r3, lr + str r1, [r0, #0] @ r11 + @ r12 does not need storing, it it the intra-procedure-call scratch register + str r2, [r0, #8] @ sp + str r3, [r0, #12] @ lr + str r3, [r0, #16] @ store return address as pc + @ T1 does not have a non-cpsr-clobbering register-zeroing instruction. + @ It is safe to use here though because we are about to return, and cpsr is + @ not expected to be preserved. + movs r0, #0 @ return UNW_ESUCCESS +#else + @ 32bit thumb-2 restrictions for stm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) cannot be in the list in an STM instruction + stm r0, {r0-r12} + str sp, [r0, #52] + str lr, [r0, #56] + str lr, [r0, #60] @ store return address as pc + mov r0, #0 @ return UNW_ESUCCESS +#endif + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPv) + vstmia r0, {d0-d15} + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3-d16 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPv) + vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .fpu vfpv3 +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPv) + @ VFP and iwMMX instructions are only available when compiling with the flags + @ that enable them. We do not want to do that in the library (because we do not + @ want the compiler to generate instructions that access those) but this is + @ only accessed if the personality routine needs these registers. Use of + @ these registers implies they are, actually, available on the target, so + @ it's ok to execute. + @ So, generate the instructions using the corresponding coprocessor mnemonic. + vstmia r0, {d16-d31} + JMP(lr) + +#if defined(_LIBUNWIND_ARM_WMMX) + +@ +@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPv) + stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8 + stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8 + stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8 + stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8 + stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8 + stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8 + stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8 + stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8 + stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8 + stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8 + stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8 + stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8 + stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8 + stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8 + stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8 + stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8 + JMP(lr) + +@ +@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values) +@ +@ On entry: +@ values pointer is in r0 +@ + .p2align 2 +#if defined(__ELF__) + .arch armv5te +#endif +DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj) + stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4 + stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4 + stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4 + stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4 + JMP(lr) + +#endif + +#elif defined(__or1k__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in r3 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + l.sw 0(r3), r0 + l.sw 4(r3), r1 + l.sw 8(r3), r2 + l.sw 12(r3), r3 + l.sw 16(r3), r4 + l.sw 20(r3), r5 + l.sw 24(r3), r6 + l.sw 28(r3), r7 + l.sw 32(r3), r8 + l.sw 36(r3), r9 + l.sw 40(r3), r10 + l.sw 44(r3), r11 + l.sw 48(r3), r12 + l.sw 52(r3), r13 + l.sw 56(r3), r14 + l.sw 60(r3), r15 + l.sw 64(r3), r16 + l.sw 68(r3), r17 + l.sw 72(r3), r18 + l.sw 76(r3), r19 + l.sw 80(r3), r20 + l.sw 84(r3), r21 + l.sw 88(r3), r22 + l.sw 92(r3), r23 + l.sw 96(r3), r24 + l.sw 100(r3), r25 + l.sw 104(r3), r26 + l.sw 108(r3), r27 + l.sw 112(r3), r28 + l.sw 116(r3), r29 + l.sw 120(r3), r30 + l.sw 124(r3), r31 + # store ra to pc + l.sw 128(r3), r9 + # zero epcr + l.sw 132(r3), r0 + +#elif defined(__hexagon__) +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in r0 +# +#define OFFSET(offset) (offset/4) +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + memw(r0+#32) = r8 + memw(r0+#36) = r9 + memw(r0+#40) = r10 + memw(r0+#44) = r11 + + memw(r0+#48) = r12 + memw(r0+#52) = r13 + memw(r0+#56) = r14 + memw(r0+#60) = r15 + + memw(r0+#64) = r16 + memw(r0+#68) = r17 + memw(r0+#72) = r18 + memw(r0+#76) = r19 + + memw(r0+#80) = r20 + memw(r0+#84) = r21 + memw(r0+#88) = r22 + memw(r0+#92) = r23 + + memw(r0+#96) = r24 + memw(r0+#100) = r25 + memw(r0+#104) = r26 + memw(r0+#108) = r27 + + memw(r0+#112) = r28 + memw(r0+#116) = r29 + memw(r0+#120) = r30 + memw(r0+#124) = r31 + r1 = c4 // Predicate register + memw(r0+#128) = r1 + r1 = memw(r30) // *FP == Saved FP + r1 = r31 + memw(r0+#132) = r1 + + jumpr r31 + +#elif defined(__sparc__) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in o0 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + ta 3 + add %o7, 8, %o7 + std %g0, [%o0 + 0] + std %g2, [%o0 + 8] + std %g4, [%o0 + 16] + std %g6, [%o0 + 24] + std %o0, [%o0 + 32] + std %o2, [%o0 + 40] + std %o4, [%o0 + 48] + std %o6, [%o0 + 56] + std %l0, [%o0 + 64] + std %l2, [%o0 + 72] + std %l4, [%o0 + 80] + std %l6, [%o0 + 88] + std %i0, [%o0 + 96] + std %i2, [%o0 + 104] + std %i4, [%o0 + 112] + std %i6, [%o0 + 120] + jmp %o7 + clr %o0 // return UNW_ESUCCESS + +#elif defined(__riscv) + +# +# extern int __unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in a0 +# +DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext) + ISTORE x1, (RISCV_ISIZE * 0)(a0) // store ra as pc + ISTORE x1, (RISCV_ISIZE * 1)(a0) + ISTORE x2, (RISCV_ISIZE * 2)(a0) + ISTORE x3, (RISCV_ISIZE * 3)(a0) + ISTORE x4, (RISCV_ISIZE * 4)(a0) + ISTORE x5, (RISCV_ISIZE * 5)(a0) + ISTORE x6, (RISCV_ISIZE * 6)(a0) + ISTORE x7, (RISCV_ISIZE * 7)(a0) + ISTORE x8, (RISCV_ISIZE * 8)(a0) + ISTORE x9, (RISCV_ISIZE * 9)(a0) + ISTORE x10, (RISCV_ISIZE * 10)(a0) + ISTORE x11, (RISCV_ISIZE * 11)(a0) + ISTORE x12, (RISCV_ISIZE * 12)(a0) + ISTORE x13, (RISCV_ISIZE * 13)(a0) + ISTORE x14, (RISCV_ISIZE * 14)(a0) + ISTORE x15, (RISCV_ISIZE * 15)(a0) + ISTORE x16, (RISCV_ISIZE * 16)(a0) + ISTORE x17, (RISCV_ISIZE * 17)(a0) + ISTORE x18, (RISCV_ISIZE * 18)(a0) + ISTORE x19, (RISCV_ISIZE * 19)(a0) + ISTORE x20, (RISCV_ISIZE * 20)(a0) + ISTORE x21, (RISCV_ISIZE * 21)(a0) + ISTORE x22, (RISCV_ISIZE * 22)(a0) + ISTORE x23, (RISCV_ISIZE * 23)(a0) + ISTORE x24, (RISCV_ISIZE * 24)(a0) + ISTORE x25, (RISCV_ISIZE * 25)(a0) + ISTORE x26, (RISCV_ISIZE * 26)(a0) + ISTORE x27, (RISCV_ISIZE * 27)(a0) + ISTORE x28, (RISCV_ISIZE * 28)(a0) + ISTORE x29, (RISCV_ISIZE * 29)(a0) + ISTORE x30, (RISCV_ISIZE * 30)(a0) + ISTORE x31, (RISCV_ISIZE * 31)(a0) + +# if defined(__riscv_flen) + FSTORE f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0) + FSTORE f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0) + FSTORE f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0) + FSTORE f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0) + FSTORE f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0) + FSTORE f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0) + FSTORE f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0) + FSTORE f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0) + FSTORE f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0) + FSTORE f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0) + FSTORE f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0) + FSTORE f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0) + FSTORE f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0) + FSTORE f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0) + FSTORE f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0) + FSTORE f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0) + FSTORE f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0) + FSTORE f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0) + FSTORE f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0) + FSTORE f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0) + FSTORE f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0) + FSTORE f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0) + FSTORE f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0) + FSTORE f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0) + FSTORE f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0) + FSTORE f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0) + FSTORE f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0) + FSTORE f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0) + FSTORE f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0) + FSTORE f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0) + FSTORE f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0) + FSTORE f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0) +# endif + + li a0, 0 // return UNW_ESUCCESS + ret // jump to ra +#endif + + WEAK_ALIAS(__unw_getcontext, unw_getcontext) + +#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */ + +NO_EXEC_STACK_DIRECTIVE diff --git a/libunwind/src/Unwind_AppleExtras.cpp b/libunwind/src/Unwind_AppleExtras.cpp new file mode 100644 index 0000000000..e3d41ca2b4 --- /dev/null +++ b/libunwind/src/Unwind_AppleExtras.cpp @@ -0,0 +1,113 @@ +//===--------------------- Unwind_AppleExtras.cpp -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +#include "config.h" + + +// static linker symbols to prevent wrong two level namespace for _Unwind symbols +#if defined(__arm__) + #define NOT_HERE_BEFORE_5_0(sym) \ + extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \ + extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \ + extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\ + __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \ + extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \ + extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \ + extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \ + extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp43 = 0; +#elif defined(__aarch64__) + #define NOT_HERE_BEFORE_10_6(sym) + #define NEVER_HERE(sym) +#else + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #define NEVER_HERE(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ + extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp6 = 0; +#endif + + +#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + +// +// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_10_6(_Unwind_DeleteException) +NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE) +NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind) +NOT_HERE_BEFORE_10_6(_Unwind_GetGR) +NOT_HERE_BEFORE_10_6(_Unwind_GetIP) +NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_10_6(_Unwind_RaiseException) +NOT_HERE_BEFORE_10_6(_Unwind_Resume) +NOT_HERE_BEFORE_10_6(_Unwind_SetGR) +NOT_HERE_BEFORE_10_6(_Unwind_SetIP) +NOT_HERE_BEFORE_10_6(_Unwind_Backtrace) +NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction) +NOT_HERE_BEFORE_10_6(_Unwind_GetCFA) +NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow) +NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_10_6(__register_frame) +NOT_HERE_BEFORE_10_6(__deregister_frame) + +// +// symbols in libSystem.dylib for compatibility, but we don't want any new code +// using them +// +NEVER_HERE(__register_frame_info_bases) +NEVER_HERE(__register_frame_info) +NEVER_HERE(__register_frame_info_table_bases) +NEVER_HERE(__register_frame_info_table) +NEVER_HERE(__register_frame_table) +NEVER_HERE(__deregister_frame_info) +NEVER_HERE(__deregister_frame_info_bases) + +#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS) + + + + +#if defined(_LIBUNWIND_BUILD_SJLJ_APIS) +// +// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_5_0(_Unwind_GetIP) +NOT_HERE_BEFORE_5_0(_Unwind_SetGR) +NOT_HERE_BEFORE_5_0(_Unwind_SetIP) +NOT_HERE_BEFORE_5_0(_Unwind_DeleteException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register) +NOT_HERE_BEFORE_5_0(_Unwind_GetGR) +NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_5_0(_Unwind_GetCFA) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) + +#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h new file mode 100644 index 0000000000..e38d323369 --- /dev/null +++ b/libunwind/src/assembly.h @@ -0,0 +1,230 @@ +/* ===-- assembly.h - libUnwind assembler support macros -------------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + * ===----------------------------------------------------------------------=== + * + * This file defines macros for use in libUnwind assembler source. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef UNWIND_ASSEMBLY_H +#define UNWIND_ASSEMBLY_H + +#if (defined(__i386__) || defined(__x86_64__)) && defined(__linux__) +#include +#define _LIBUNWIND_CET_ENDBR _CET_ENDBR +#else +#define _LIBUNWIND_CET_ENDBR +#endif + +#if defined(__powerpc64__) +#define SEPARATOR ; +#define PPC64_OFFS_SRR0 0 +#define PPC64_OFFS_CR 272 +#define PPC64_OFFS_XER 280 +#define PPC64_OFFS_LR 288 +#define PPC64_OFFS_CTR 296 +#define PPC64_OFFS_VRSAVE 304 +#define PPC64_OFFS_FP 312 +#define PPC64_OFFS_V 824 +#elif defined(__APPLE__) && defined(__aarch64__) +#define SEPARATOR %% +#elif defined(__riscv) +# define RISCV_ISIZE (__riscv_xlen / 8) +# define RISCV_FOFFSET (RISCV_ISIZE * 32) +# if defined(__riscv_flen) +# define RISCV_FSIZE (__riscv_flen / 8) +# endif + +# if __riscv_xlen == 64 +# define ILOAD ld +# define ISTORE sd +# elif __riscv_xlen == 32 +# define ILOAD lw +# define ISTORE sw +# else +# error "Unsupported __riscv_xlen" +# endif + +# if defined(__riscv_flen) +# if __riscv_flen == 64 +# define FLOAD fld +# define FSTORE fsd +# elif __riscv_flen == 32 +# define FLOAD flw +# define FSTORE fsw +# else +# error "Unsupported __riscv_flen" +# endif +# endif +# define SEPARATOR ; +#else +#define SEPARATOR ; +#endif + +#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) +#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR +#define PPC64_OPD2 SEPARATOR \ + .p2align 3 SEPARATOR \ + .quad .Lfunc_begin0 SEPARATOR \ + .quad .TOC.@tocbase SEPARATOR \ + .quad 0 SEPARATOR \ + .text SEPARATOR \ +.Lfunc_begin0: +#else +#define PPC64_OPD1 +#define PPC64_OPD2 +#endif + +#if defined(__ARM_FEATURE_BTI_DEFAULT) + .pushsection ".note.gnu.property", "a" SEPARATOR \ + .balign 8 SEPARATOR \ + .long 4 SEPARATOR \ + .long 0x10 SEPARATOR \ + .long 0x5 SEPARATOR \ + .asciz "GNU" SEPARATOR \ + .long 0xc0000000 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \ + .long 4 SEPARATOR \ + .long 3 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI AND */ \ + /* GNU_PROPERTY_AARCH64_FEATURE_1_PAC */ \ + .long 0 SEPARATOR \ + .popsection SEPARATOR +#define AARCH64_BTI bti c +#else +#define AARCH64_BTI +#endif + +#define GLUE2(a, b) a ## b +#define GLUE(a, b) GLUE2(a, b) +#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) + +#if defined(__APPLE__) + +#define SYMBOL_IS_FUNC(name) +#define HIDDEN_SYMBOL(name) .private_extern name +#if defined(_LIBUNWIND_HIDE_SYMBOLS) +#define EXPORT_SYMBOL(name) HIDDEN_SYMBOL(name) +#else +#define EXPORT_SYMBOL(name) +#endif +#define WEAK_ALIAS(name, aliasname) \ + .globl SYMBOL_NAME(aliasname) SEPARATOR \ + EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__ELF__) + +#if defined(__arm__) +#define SYMBOL_IS_FUNC(name) .type name,%function +#else +#define SYMBOL_IS_FUNC(name) .type name,@function +#endif +#define HIDDEN_SYMBOL(name) .hidden name +#if defined(_LIBUNWIND_HIDE_SYMBOLS) +#define EXPORT_SYMBOL(name) HIDDEN_SYMBOL(name) +#else +#define EXPORT_SYMBOL(name) +#endif +#define WEAK_SYMBOL(name) .weak name + +#if defined(__hexagon__) +#define WEAK_ALIAS(name, aliasname) \ + EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + WEAK_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + .equiv SYMBOL_NAME(aliasname), SYMBOL_NAME(name) +#else +#define WEAK_ALIAS(name, aliasname) \ + EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + WEAK_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) +#endif + +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ + defined(__linux__) +#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits +#else +#define NO_EXEC_STACK_DIRECTIVE +#endif + +#elif defined(_WIN32) + +#define SYMBOL_IS_FUNC(name) \ + .def name SEPARATOR \ + .scl 2 SEPARATOR \ + .type 32 SEPARATOR \ + .endef +#define EXPORT_SYMBOL2(name) \ + .section .drectve,"yn" SEPARATOR \ + .ascii "-export:", #name, "\0" SEPARATOR \ + .text +#if defined(_LIBUNWIND_HIDE_SYMBOLS) +#define EXPORT_SYMBOL(name) +#else +#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name) +#endif +#define HIDDEN_SYMBOL(name) + +#if defined(__MINGW32__) +#define WEAK_ALIAS(name, aliasname) \ + .globl SYMBOL_NAME(aliasname) SEPARATOR \ + EXPORT_SYMBOL(aliasname) SEPARATOR \ + SYMBOL_NAME(aliasname) = SYMBOL_NAME(name) +#else +#define WEAK_ALIAS3(name, aliasname) \ + .section .drectve,"yn" SEPARATOR \ + .ascii "-alternatename:", #aliasname, "=", #name, "\0" SEPARATOR \ + .text +#define WEAK_ALIAS2(name, aliasname) \ + WEAK_ALIAS3(name, aliasname) +#define WEAK_ALIAS(name, aliasname) \ + EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR \ + WEAK_ALIAS2(SYMBOL_NAME(name), SYMBOL_NAME(aliasname)) +#endif + +#define NO_EXEC_STACK_DIRECTIVE + +#elif defined(__sparc__) + +#else + +#error Unsupported target + +#endif + +#define DEFINE_LIBUNWIND_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + PPC64_OPD1 \ + SYMBOL_NAME(name): \ + PPC64_OPD2 \ + AARCH64_BTI + +#if defined(__arm__) +#if !defined(__ARM_ARCH) +#define __ARM_ARCH 4 +#endif + +#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 +#define ARM_HAS_BX +#endif + +#ifdef ARM_HAS_BX +#define JMP(r) bx r +#else +#define JMP(r) mov pc, r +#endif +#endif /* __arm__ */ + +#if defined(__ppc__) || defined(__powerpc64__) +#define PPC_LEFT_SHIFT(index) << (index) +#endif + +#endif /* UNWIND_ASSEMBLY_H */ diff --git a/libunwind/src/cet_unwind.h b/libunwind/src/cet_unwind.h new file mode 100644 index 0000000000..482e0c8086 --- /dev/null +++ b/libunwind/src/cet_unwind.h @@ -0,0 +1,41 @@ +//===--------------------------- cet_unwind.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +//===----------------------------------------------------------------------===// + +#ifndef LIBUNWIND_CET_UNWIND_H +#define LIBUNWIND_CET_UNWIND_H + +#include "libunwind.h" + +// Currently, CET is implemented on Linux x86 platforms. +#if defined(_LIBUNWIND_TARGET_LINUX) && defined(__CET__) && defined(__SHSTK__) +#define _LIBUNWIND_USE_CET 1 +#endif + +#if defined(_LIBUNWIND_USE_CET) +#include +#include + +#define _LIBUNWIND_POP_CET_SSP(x) \ + do { \ + unsigned long ssp = _get_ssp(); \ + if (ssp != 0) { \ + unsigned int tmp = (x); \ + while (tmp > 255) { \ + _inc_ssp(255); \ + tmp -= 255; \ + } \ + _inc_ssp(tmp); \ + } \ + } while (0) +#endif + +extern void *__libunwind_cet_get_registers(unw_cursor_t *); +extern void *__libunwind_cet_get_jump_target(); + +#endif diff --git a/libunwind/src/config.h b/libunwind/src/config.h new file mode 100644 index 0000000000..2ab9d2f5e0 --- /dev/null +++ b/libunwind/src/config.h @@ -0,0 +1,241 @@ +//===----------------------------- config.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Defines macros used within libunwind project. +// +//===----------------------------------------------------------------------===// + + +#ifndef LIBUNWIND_CONFIG_H +#define LIBUNWIND_CONFIG_H + +#include +#include +#include +#include + +#include <__libunwind_config.h> + +// Platform specific configuration defines. +#ifdef __APPLE__ + #if defined(FOR_DYLD) + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #else + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #endif +#elif defined(_WIN32) + #ifdef __SEH__ + #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1 + #else + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #endif +#elif defined(_LIBUNWIND_IS_BAREMETAL) + #if !defined(_LIBUNWIND_ARM_EHABI) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #endif +#elif defined(__BIONIC__) && defined(_LIBUNWIND_ARM_EHABI) + // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After + // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster. + #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1 +#else + // Assume an ELF system with a dl_iterate_phdr function. + #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1 + #if !defined(_LIBUNWIND_ARM_EHABI) + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1 + #endif +#endif + +#if defined(_LIBUNWIND_HIDE_SYMBOLS) + // The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility. + #define _LIBUNWIND_EXPORT + #define _LIBUNWIND_HIDDEN +#else + #if !defined(__ELF__) && !defined(__MACH__) + #define _LIBUNWIND_EXPORT __declspec(dllexport) + #define _LIBUNWIND_HIDDEN + #else + #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) + #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) + #endif +#endif + +#define STR(a) #a +#define XSTR(a) STR(a) +#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name + +#if defined(__APPLE__) +#if defined(_LIBUNWIND_HIDE_SYMBOLS) +#define _LIBUNWIND_ALIAS_VISIBILITY(name) __asm__(".private_extern " name); +#else +#define _LIBUNWIND_ALIAS_VISIBILITY(name) +#endif +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + __asm__(".globl " SYMBOL_NAME(aliasname)); \ + __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \ + _LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname)) +#elif defined(__ELF__) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((weak, alias(#name))); +#elif defined(_WIN32) +#if defined(__MINGW32__) +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname \ + __attribute__((alias(#name))); +#else +#define _LIBUNWIND_WEAK_ALIAS(name, aliasname) \ + __pragma(comment(linker, "/alternatename:" SYMBOL_NAME(aliasname) "=" \ + SYMBOL_NAME(name))) \ + extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname; +#endif +#else +#error Unsupported target +#endif + +// Apple/armv7k defaults to DWARF/Compact unwinding, but its libunwind also +// needs to include the SJLJ APIs. +#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__) +#define _LIBUNWIND_BUILD_SJLJ_APIS +#endif + +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) +#define _LIBUNWIND_SUPPORT_FRAME_APIS +#endif + +#if defined(__i386__) || defined(__x86_64__) || \ + defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \ + (!defined(__APPLE__) && defined(__arm__)) || \ + defined(__aarch64__) || \ + defined(__mips__) || \ + defined(__riscv) || \ + defined(__hexagon__) +#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS) +#define _LIBUNWIND_BUILD_ZERO_COST_APIS +#endif +#endif + +#ifndef _LIBUNWIND_REMEMBER_HEAP_ALLOC +#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) || \ + defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) || \ + defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) \ + do { \ + } while (0) +#elif defined(_WIN32) +#define _LIBUNWIND_REMEMBER_ALLOC(_size) _malloca(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) _freea(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED +#else +#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED +#endif +#else /* _LIBUNWIND_REMEMBER_HEAP_ALLOC */ +#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size) +#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr) +#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_ABORT(msg) \ + do { \ + abort(); \ + } while (0) +#else +#define _LIBUNWIND_ABORT(msg) \ + do { \ + fprintf(stderr, "libunwind: %s - %s\n", __func__, msg); \ + fflush(stderr); \ + abort(); \ + } while (0) +#endif + +#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL) +#define _LIBUNWIND_LOG0(msg) +#define _LIBUNWIND_LOG(msg, ...) +#else +#define _LIBUNWIND_LOG0(msg) \ + fprintf(stderr, "libunwind: " msg "\n") +#define _LIBUNWIND_LOG(msg, ...) \ + fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__) +#endif + +#if defined(NDEBUG) + #define _LIBUNWIND_LOG_IF_FALSE(x) x +#else + #define _LIBUNWIND_LOG_IF_FALSE(x) \ + do { \ + bool _ret = x; \ + if (!_ret) \ + _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \ + } while (0) +#endif + +// Macros that define away in non-Debug builds +#ifdef NDEBUG + #define _LIBUNWIND_DEBUG_LOG(msg, ...) + #define _LIBUNWIND_TRACE_API(msg, ...) + #define _LIBUNWIND_TRACING_UNWINDING (0) + #define _LIBUNWIND_TRACING_DWARF (0) + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) + #define _LIBUNWIND_TRACE_DWARF(...) +#else + #ifdef __cplusplus + extern "C" { + #endif + extern bool logAPIs(); + extern bool logUnwinding(); + extern bool logDWARF(); + #ifdef __cplusplus + } + #endif + #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) + #define _LIBUNWIND_TRACE_API(msg, ...) \ + do { \ + if (logAPIs()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) + #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() + #define _LIBUNWIND_TRACING_DWARF logDWARF() + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ + do { \ + if (logUnwinding()) \ + _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while (0) + #define _LIBUNWIND_TRACE_DWARF(...) \ + do { \ + if (logDWARF()) \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#endif + +#ifdef __cplusplus +// Used to fit UnwindCursor and Registers_xxx types against unw_context_t / +// unw_cursor_t sized memory blocks. +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# define COMP_OP == +#else +# define COMP_OP <= +#endif +template +struct check_fit { + template + struct blk_count { + static const size_t count = + (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t); + }; + static const bool does_fit = + (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count); +}; +#undef COMP_OP +#endif // __cplusplus + +#endif // LIBUNWIND_CONFIG_H diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h new file mode 100644 index 0000000000..40f0daf468 --- /dev/null +++ b/libunwind/src/dwarf2.h @@ -0,0 +1,239 @@ +//===------------------------------- dwarf2.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + + +/* + These constants were taken from version 3 of the DWARF standard, + which is Copyright (c) 2005 Free Standards Group, and + Copyright (c) 1992, 1993 UNIX International, Inc. +*/ + +#ifndef __DWARF2__ +#define __DWARF2__ + +// DWARF unwind instructions +enum { + DW_CFA_nop = 0x0, + DW_CFA_set_loc = 0x1, + DW_CFA_advance_loc1 = 0x2, + DW_CFA_advance_loc2 = 0x3, + DW_CFA_advance_loc4 = 0x4, + DW_CFA_offset_extended = 0x5, + DW_CFA_restore_extended = 0x6, + DW_CFA_undefined = 0x7, + DW_CFA_same_value = 0x8, + DW_CFA_register = 0x9, + DW_CFA_remember_state = 0xA, + DW_CFA_restore_state = 0xB, + DW_CFA_def_cfa = 0xC, + DW_CFA_def_cfa_register = 0xD, + DW_CFA_def_cfa_offset = 0xE, + DW_CFA_def_cfa_expression = 0xF, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta + DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register + DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register + + // GNU extensions + DW_CFA_GNU_window_save = 0x2D, + DW_CFA_GNU_args_size = 0x2E, + DW_CFA_GNU_negative_offset_extended = 0x2F, + + // AARCH64 extensions + DW_CFA_AARCH64_negate_ra_state = 0x2D +}; + + +// FSF exception handling Pointer-Encoding constants +// Used in CFI augmentation by GCC +enum { + DW_EH_PE_ptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_absptr = 0x00, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + DW_EH_PE_indirect = 0x80, + DW_EH_PE_omit = 0xFF +}; + + +// DWARF expressions +enum { + DW_OP_addr = 0x03, // constant address (size target specific) + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, // 1-byte constant + DW_OP_const1s = 0x09, // 1-byte constant + DW_OP_const2u = 0x0A, // 2-byte constant + DW_OP_const2s = 0x0B, // 2-byte constant + DW_OP_const4u = 0x0C, // 4-byte constant + DW_OP_const4s = 0x0D, // 4-byte constant + DW_OP_const8u = 0x0E, // 8-byte constant + DW_OP_const8s = 0x0F, // 8-byte constant + DW_OP_constu = 0x10, // ULEB128 constant + DW_OP_consts = 0x11, // SLEB128 constant + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, // 1-byte stack index + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1A, + DW_OP_div = 0x1B, + DW_OP_minus = 0x1C, + DW_OP_mod = 0x1D, + DW_OP_mul = 0x1E, + DW_OP_neg = 0x1F, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, // ULEB128 addend + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2F, // signed 2-byte constant + DW_OP_bra = 0x28, // signed 2-byte constant + DW_OP_eq = 0x29, + DW_OP_ge = 0x2A, + DW_OP_gt = 0x2B, + DW_OP_le = 0x2C, + DW_OP_lt = 0x2D, + DW_OP_ne = 0x2E, + DW_OP_lit0 = 0x30, // Literal 0 + DW_OP_lit1 = 0x31, // Literal 1 + DW_OP_lit2 = 0x32, // Literal 2 + DW_OP_lit3 = 0x33, // Literal 3 + DW_OP_lit4 = 0x34, // Literal 4 + DW_OP_lit5 = 0x35, // Literal 5 + DW_OP_lit6 = 0x36, // Literal 6 + DW_OP_lit7 = 0x37, // Literal 7 + DW_OP_lit8 = 0x38, // Literal 8 + DW_OP_lit9 = 0x39, // Literal 9 + DW_OP_lit10 = 0x3A, // Literal 10 + DW_OP_lit11 = 0x3B, // Literal 11 + DW_OP_lit12 = 0x3C, // Literal 12 + DW_OP_lit13 = 0x3D, // Literal 13 + DW_OP_lit14 = 0x3E, // Literal 14 + DW_OP_lit15 = 0x3F, // Literal 15 + DW_OP_lit16 = 0x40, // Literal 16 + DW_OP_lit17 = 0x41, // Literal 17 + DW_OP_lit18 = 0x42, // Literal 18 + DW_OP_lit19 = 0x43, // Literal 19 + DW_OP_lit20 = 0x44, // Literal 20 + DW_OP_lit21 = 0x45, // Literal 21 + DW_OP_lit22 = 0x46, // Literal 22 + DW_OP_lit23 = 0x47, // Literal 23 + DW_OP_lit24 = 0x48, // Literal 24 + DW_OP_lit25 = 0x49, // Literal 25 + DW_OP_lit26 = 0x4A, // Literal 26 + DW_OP_lit27 = 0x4B, // Literal 27 + DW_OP_lit28 = 0x4C, // Literal 28 + DW_OP_lit29 = 0x4D, // Literal 29 + DW_OP_lit30 = 0x4E, // Literal 30 + DW_OP_lit31 = 0x4F, // Literal 31 + DW_OP_reg0 = 0x50, // Contents of reg0 + DW_OP_reg1 = 0x51, // Contents of reg1 + DW_OP_reg2 = 0x52, // Contents of reg2 + DW_OP_reg3 = 0x53, // Contents of reg3 + DW_OP_reg4 = 0x54, // Contents of reg4 + DW_OP_reg5 = 0x55, // Contents of reg5 + DW_OP_reg6 = 0x56, // Contents of reg6 + DW_OP_reg7 = 0x57, // Contents of reg7 + DW_OP_reg8 = 0x58, // Contents of reg8 + DW_OP_reg9 = 0x59, // Contents of reg9 + DW_OP_reg10 = 0x5A, // Contents of reg10 + DW_OP_reg11 = 0x5B, // Contents of reg11 + DW_OP_reg12 = 0x5C, // Contents of reg12 + DW_OP_reg13 = 0x5D, // Contents of reg13 + DW_OP_reg14 = 0x5E, // Contents of reg14 + DW_OP_reg15 = 0x5F, // Contents of reg15 + DW_OP_reg16 = 0x60, // Contents of reg16 + DW_OP_reg17 = 0x61, // Contents of reg17 + DW_OP_reg18 = 0x62, // Contents of reg18 + DW_OP_reg19 = 0x63, // Contents of reg19 + DW_OP_reg20 = 0x64, // Contents of reg20 + DW_OP_reg21 = 0x65, // Contents of reg21 + DW_OP_reg22 = 0x66, // Contents of reg22 + DW_OP_reg23 = 0x67, // Contents of reg23 + DW_OP_reg24 = 0x68, // Contents of reg24 + DW_OP_reg25 = 0x69, // Contents of reg25 + DW_OP_reg26 = 0x6A, // Contents of reg26 + DW_OP_reg27 = 0x6B, // Contents of reg27 + DW_OP_reg28 = 0x6C, // Contents of reg28 + DW_OP_reg29 = 0x6D, // Contents of reg29 + DW_OP_reg30 = 0x6E, // Contents of reg30 + DW_OP_reg31 = 0x6F, // Contents of reg31 + DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset + DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset + DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset + DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset + DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset + DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset + DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset + DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset + DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset + DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset + DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset + DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset + DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset + DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset + DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset + DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset + DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset + DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset + DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset + DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset + DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset + DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset + DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset + DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset + DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset + DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset + DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset + DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset + DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset + DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset + DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset + DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset + DW_OP_regx = 0x90, // ULEB128 register + DW_OP_fbreg = 0x91, // SLEB128 offset + DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset + DW_OP_piece = 0x93, // ULEB128 size of piece addressed + DW_OP_deref_size = 0x94, // 1-byte size of data retrieved + DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved + DW_OP_nop = 0x96, + DW_OP_push_object_addres = 0x97, + DW_OP_call2 = 0x98, // 2-byte offset of DIE + DW_OP_call4 = 0x99, // 4-byte offset of DIE + DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE + DW_OP_lo_user = 0xE0, + DW_OP_APPLE_uninit = 0xF0, + DW_OP_hi_user = 0xFF +}; + + +#endif diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp new file mode 100644 index 0000000000..93e1bc131f --- /dev/null +++ b/libunwind/src/libunwind.cpp @@ -0,0 +1,341 @@ +//===--------------------------- libunwind.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Implements unw_* functions from +// +//===----------------------------------------------------------------------===// + +#include + +#include "config.h" +#include "libunwind_ext.h" + +#include + +// Define the __has_feature extension for compilers that do not support it so +// that we can later check for the presence of ASan in a compiler-neutral way. +#if !defined(__has_feature) +#define __has_feature(feature) 0 +#endif + +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#include +#endif + +#if !defined(__USING_SJLJ_EXCEPTIONS__) +#include "AddressSpace.hpp" +#include "UnwindCursor.hpp" + +using namespace libunwind; + +/// internal object to represent this processes address space +LocalAddressSpace LocalAddressSpace::sThisAddressSpace; + +_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = + (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; + +/// Create a cursor of a thread in this process given 'context' recorded by +/// __unw_getcontext(). +_LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, + unw_context_t *context) { + _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)", + static_cast(cursor), + static_cast(context)); +#if defined(__i386__) +# define REGISTER_KIND Registers_x86 +#elif defined(__x86_64__) +# define REGISTER_KIND Registers_x86_64 +#elif defined(__powerpc64__) +# define REGISTER_KIND Registers_ppc64 +#elif defined(__ppc__) +# define REGISTER_KIND Registers_ppc +#elif defined(__aarch64__) +# define REGISTER_KIND Registers_arm64 +#elif defined(__arm__) +# define REGISTER_KIND Registers_arm +#elif defined(__or1k__) +# define REGISTER_KIND Registers_or1k +#elif defined(__hexagon__) +# define REGISTER_KIND Registers_hexagon +#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 +# define REGISTER_KIND Registers_mips_o32 +#elif defined(__mips64) +# define REGISTER_KIND Registers_mips_newabi +#elif defined(__mips__) +# warning The MIPS architecture is not supported with this ABI and environment! +#elif defined(__sparc__) +# define REGISTER_KIND Registers_sparc +#elif defined(__riscv) +# define REGISTER_KIND Registers_riscv +#elif defined(__ve__) +# define REGISTER_KIND Registers_ve +#else +# error Architecture not supported +#endif + // Use "placement new" to allocate UnwindCursor in the cursor buffer. + new (reinterpret_cast *>(cursor)) + UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#undef REGISTER_KIND + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->setInfoBasedOnIPRegister(); + + return UNW_ESUCCESS; +} +_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local) + +/// Get value of specified register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t *value) { + _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)", + static_cast(cursor), regNum, + static_cast(value)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + *value = co->getReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg) + +/// Set value of specified register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t value) { + _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR + ")", + static_cast(cursor), regNum, value); + typedef LocalAddressSpace::pint_t pint_t; + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + co->setReg(regNum, (pint_t)value); + // specical case altering IP to re-find info (being called by personality + // function) + if (regNum == UNW_REG_IP) { + unw_proc_info_t info; + // First, get the FDE for the old location and then update it. + co->getInfo(&info); + co->setInfoBasedOnIPRegister(false); + // If the original call expects stack adjustment, perform this now. + // Normal frame unwinding would have included the offset already in the + // CFA computation. + // Note: for PA-RISC and other platforms where the stack grows up, + // this should actually be - info.gp. LLVM doesn't currently support + // any such platforms and Clang doesn't export a macro for them. + if (info.gp) + co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp); + } + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg) + +/// Get value of specified float register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t *value) { + _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", + static_cast(cursor), regNum, + static_cast(value)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + *value = co->getFloatReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg) + +/// Set value of specified float register at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t value) { +#if defined(_LIBUNWIND_ARM_EHABI) + _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", + static_cast(cursor), regNum, value); +#else + _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", + static_cast(cursor), regNum, value); +#endif + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + co->setFloatReg(regNum, value); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} +_LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg) + +/// Move cursor to next frame. +_LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->step(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step) + +/// Get unwind info at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor, + unw_proc_info_t *info) { + _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)", + static_cast(cursor), static_cast(info)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->getInfo(info); + if (info->end_ip == 0) + return UNW_ENOINFO; + return UNW_ESUCCESS; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info) + +/// Resume execution at cursor position (aka longjump). +_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast(cursor)); +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + // Inform the ASan runtime that now might be a good time to clean stuff up. + __asan_handle_no_return(); +#endif + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->jumpto(); + return UNW_EUNSPEC; +} +_LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume) + +/// Get name of function at cursor position in stack frame. +_LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf, + size_t bufLen, unw_word_t *offset) { + _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", + static_cast(cursor), static_cast(buf), + static_cast(bufLen)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->getFunctionName(buf, bufLen, offset)) + return UNW_ESUCCESS; + return UNW_EUNSPEC; +} +_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name) + +/// Checks if a register is a floating-point register. +_LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor, + unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)", + static_cast(cursor), regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->validFloatReg(regNum); +} +_LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg) + +/// Checks if a register is a floating-point register. +_LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor, + unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)", + static_cast(cursor), regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->getRegisterName(regNum); +} +_LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname) + +/// Checks if current frame is signal trampoline. +_LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)", + static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->isSignalFrame(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame) + +#ifdef __arm__ +// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD +_LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)", + static_cast(cursor)); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->saveVFPAsX(); +} +_LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X) +#endif + + +#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +/// SPI: walks cached DWARF entries +_LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)", + reinterpret_cast(func)); + DwarfFDECache::iterateCacheEntries(func); +} +_LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache, + unw_iterate_dwarf_unwind_cache) + +/// IPI: for __register_frame() +void __unw_add_dynamic_fde(unw_word_t fde) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + const char *message = CFI_Parser::decodeFDE( + LocalAddressSpace::sThisAddressSpace, + (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); + if (message == NULL) { + // dynamically registered FDEs don't have a mach_header group they are in. + // Use fde as mh_group + unw_word_t mh_group = fdeInfo.fdeStart; + DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } else { + _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message); + } +} + +/// IPI: for __deregister_frame() +void __unw_remove_dynamic_fde(unw_word_t fde) { + // fde is own mh_group + DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); +} +#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) +#endif // !defined(__USING_SJLJ_EXCEPTIONS__) + + + +// Add logging hooks in Debug builds only +#ifndef NDEBUG +#include + +_LIBUNWIND_HIDDEN +bool logAPIs() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); + checked = true; + } + return log; +} + +_LIBUNWIND_HIDDEN +bool logUnwinding() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); + checked = true; + } + return log; +} + +_LIBUNWIND_HIDDEN +bool logDWARF() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); + checked = true; + } + return log; +} + +#endif // NDEBUG + diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h new file mode 100644 index 0000000000..316dee2982 --- /dev/null +++ b/libunwind/src/libunwind_ext.h @@ -0,0 +1,65 @@ +//===------------------------ libunwind_ext.h -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// +// Extensions to libunwind API. +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBUNWIND_EXT__ +#define __LIBUNWIND_EXT__ + +#include "config.h" +#include +#include + +#define UNW_STEP_SUCCESS 1 +#define UNW_STEP_END 0 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int __unw_getcontext(unw_context_t *); +extern int __unw_init_local(unw_cursor_t *, unw_context_t *); +extern int __unw_step(unw_cursor_t *); +extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *); +extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *); +extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t); +extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t); +extern int __unw_resume(unw_cursor_t *); + +#ifdef __arm__ +/* Save VFP registers in FSTMX format (instead of FSTMD). */ +extern void __unw_save_vfp_as_X(unw_cursor_t *); +#endif + +extern const char *__unw_regname(unw_cursor_t *, unw_regnum_t); +extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *); +extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t); +extern int __unw_is_signal_frame(unw_cursor_t *); +extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *); + +// SPI +extern void __unw_iterate_dwarf_unwind_cache(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); + +// IPI +extern void __unw_add_dynamic_fde(unw_word_t fde); +extern void __unw_remove_dynamic_fde(unw_word_t fde); + +#if defined(_LIBUNWIND_ARM_EHABI) +extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); +extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, + const uint32_t *data, + size_t offset, size_t len); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __LIBUNWIND_EXT__ diff --git a/libunwind/test/CMakeLists.txt b/libunwind/test/CMakeLists.txt new file mode 100644 index 0000000000..932a6e3369 --- /dev/null +++ b/libunwind/test/CMakeLists.txt @@ -0,0 +1,61 @@ +include(AddLLVM) # for add_lit_testsuite +macro(pythonize_bool var) + if (${var}) + set(${var} True) + else() + set(${var} False) + endif() +endmacro() + +if (NOT DEFINED LIBCXX_ENABLE_SHARED) + set(LIBCXX_ENABLE_SHARED ON) +endif() + +pythonize_bool(LIBUNWIND_BUILD_32_BITS) +pythonize_bool(LIBUNWIND_ENABLE_CET) +pythonize_bool(LIBCXX_ENABLE_SHARED) +pythonize_bool(LIBUNWIND_ENABLE_SHARED) +pythonize_bool(LIBUNWIND_ENABLE_THREADS) +pythonize_bool(LIBUNWIND_USES_ARM_EHABI) +pythonize_bool(LIBUNWIND_USE_COMPILER_RT) +pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY) +set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING + "TargetInfo to use when setting up test environment.") +set(LIBUNWIND_EXECUTOR "${Python3_EXECUTABLE} ${LIBUNWIND_LIBCXX_PATH}/utils/run.py" CACHE STRING + "Executor to use when running tests.") + +set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not edit!") +set(SERIALIZED_LIT_PARAMS "# Lit parameters serialized here for llvm-lit to pick them up\n") + +macro(serialize_lit_param param value) + string(APPEND SERIALIZED_LIT_PARAMS "config.${param} = ${value}\n") +endmacro() + +serialize_lit_param(enable_experimental False) + +if (LLVM_USE_SANITIZER) + serialize_lit_param(use_sanitizer "\"${LLVM_USE_SANITIZER}\"") +endif() + +if (LIBUNWIND_TARGET_TRIPLE) + serialize_lit_param(target_triple "\"${LIBUNWIND_TARGET_TRIPLE}\"") +endif() + +if (LIBUNWIND_BUILD_32_BITS) + serialize_lit_param(enable_32bit True) +endif() + +foreach(param IN LISTS LIBUNWIND_TEST_PARAMS) + string(REGEX REPLACE "(.+)=(.+)" "\\1" name "${param}") + string(REGEX REPLACE "(.+)=(.+)" "\\2" value "${param}") + serialize_lit_param("${name}" "\"${value}\"") +endforeach() + +configure_lit_site_cfg( + "${LIBUNWIND_TEST_CONFIG}" + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + MAIN_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py") + +add_lit_testsuite(check-unwind "Running libunwind tests" + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS unwind ${LIBUNWIND_TEST_DEPS}) diff --git a/libunwind/test/alignment.compile.pass.cpp b/libunwind/test/alignment.compile.pass.cpp new file mode 100644 index 0000000000..4606dc5e53 --- /dev/null +++ b/libunwind/test/alignment.compile.pass.cpp @@ -0,0 +1,24 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// The Itanium ABI requires that _Unwind_Exception objects are "double-word +// aligned". + +#include + +// EHABI : 8-byte aligned +// itanium: largest supported alignment for the system +#if defined(_LIBUNWIND_ARM_EHABI) +static_assert(alignof(_Unwind_Control_Block) == 8, + "_Unwind_Control_Block must be double-word aligned"); +#else +struct MaxAligned {} __attribute__((__aligned__)); +static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned), + "_Unwind_Exception must be maximally aligned"); +#endif diff --git a/libunwind/test/floatregister.pass.cpp b/libunwind/test/floatregister.pass.cpp new file mode 100644 index 0000000000..64107e6d49 --- /dev/null +++ b/libunwind/test/floatregister.pass.cpp @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: linux && target={{aarch64-.+}} + +// Basic test for float registers number are accepted. + +#include +#include +#include +#include + +_Unwind_Reason_Code frame_handler(struct _Unwind_Context *ctx, void *arg) { + (void)arg; + Dl_info info = {0, 0, 0, 0}; + + // Unwind util the main is reached, above frames depend on the platform and + // architecture. + if (dladdr(reinterpret_cast(_Unwind_GetIP(ctx)), &info) && + info.dli_sname && !strcmp("main", info.dli_sname)) + _Exit(0); + + return _URC_NO_REASON; +} + +__attribute__((noinline)) void foo() { + // Provide some CFI directives that instructs the unwinder where given + // float register is. +#if defined(__aarch64__) + // DWARF register number for V0-V31 registers are 64-95. + // Previous value of V0 is saved at offset 0 from CFA. + asm volatile(".cfi_offset 64, 0"); + // From now on the previous value of register can't be restored anymore. + asm volatile(".cfi_undefined 65"); + asm volatile(".cfi_undefined 95"); + // Previous value of V2 is in V30. + asm volatile(".cfi_register 66, 94"); +#endif + _Unwind_Backtrace(frame_handler, NULL); +} + +int main() { + foo(); + return -2; +} diff --git a/libunwind/test/forceunwind.pass.cpp b/libunwind/test/forceunwind.pass.cpp new file mode 100644 index 0000000000..a3191f8f74 --- /dev/null +++ b/libunwind/test/forceunwind.pass.cpp @@ -0,0 +1,74 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: linux + +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +// Basic test for _Unwind_ForcedUnwind. +// See libcxxabi/test/forced_unwind* tests too. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void foo(); +_Unwind_Exception ex; + +_Unwind_Reason_Code stop(int version, _Unwind_Action actions, + _Unwind_Exception_Class exceptionClass, + _Unwind_Exception *exceptionObject, + struct _Unwind_Context *context, + void *stop_parameter) { + assert(version == 1); + assert((actions & _UA_FORCE_UNWIND) != 0); + (void)exceptionClass; + assert(exceptionObject == &ex); + assert(stop_parameter == &foo); + + Dl_info info = {0, 0, 0, 0}; + + // Unwind util the main is reached, above frames depend on the platform and + // architecture. + if (dladdr(reinterpret_cast(_Unwind_GetIP(context)), &info) && + info.dli_sname && !strcmp("main", info.dli_sname)) { + _Exit(0); + } + return _URC_NO_REASON; +} + +__attribute__((noinline)) void foo() { + + // Arm EHABI defines struct _Unwind_Control_Block as exception + // object. Ensure struct _Unwind_Exception* work there too, + // because _Unwind_Exception in this case is just an alias. + struct _Unwind_Exception *e = &ex; +#if defined(_LIBUNWIND_ARM_EHABI) + // Create a mock exception object. + memset(e, '\0', sizeof(*e)); + strcpy(reinterpret_cast(&e->exception_class), "CLNGUNW"); +#endif + _Unwind_ForcedUnwind(e, stop, (void *)&foo); +} + +int main() { + foo(); + return -2; +} diff --git a/libunwind/test/frameheadercache_test.pass.cpp b/libunwind/test/frameheadercache_test.pass.cpp new file mode 100644 index 0000000000..dd1d3dd939 --- /dev/null +++ b/libunwind/test/frameheadercache_test.pass.cpp @@ -0,0 +1,78 @@ +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +// The other libunwind tests don't test internal interfaces, so the include path +// is a little wonky. +#include "../src/config.h" + +// Only run this test under supported configurations. + +#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) && \ + defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE) + +#include +#include + +// This file defines several of the data structures needed here, +// and includes FrameHeaderCache.hpp as well. +#include "../src/AddressSpace.hpp" + +#define kBaseAddr 0xFFF000 +#define kTextSegmentLength 0xFF + +using namespace libunwind; + +int main(int, char**) { + FrameHeaderCache FHC; + struct dl_phdr_info PInfo; + memset(&PInfo, 0, sizeof(PInfo)); + // The cache itself should only care about these two fields--they + // tell the cache to invalidate or not; everything else is handled + // by AddressSpace.hpp. + PInfo.dlpi_adds = 6; + PInfo.dlpi_subs = 7; + + UnwindInfoSections UIS; + UIS.dso_base = kBaseAddr; + UIS.text_segment_length = kTextSegmentLength; + dl_iterate_cb_data CBData; + // Unused by the cache. + CBData.addressSpace = nullptr; + CBData.sects = &UIS; + CBData.targetAddr = kBaseAddr + 1; + + // Nothing present, shouldn't find. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + FHC.add(&UIS); + // Just added. Should find. + if (!FHC.find(&PInfo, 0, &CBData)) + abort(); + // Cache is invalid. Shouldn't find. + PInfo.dlpi_adds++; + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + + FHC.add(&UIS); + CBData.targetAddr = kBaseAddr - 1; + // Shouldn't find something outside of the addresses. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + // Add enough things to the cache that the entry is evicted. + for (int i = 0; i < 9; i++) { + UIS.dso_base = kBaseAddr + (kTextSegmentLength * i); + FHC.add(&UIS); + } + CBData.targetAddr = kBaseAddr; + // Should have been evicted. + if (FHC.find(&PInfo, 0, &CBData)) + abort(); + return 0; +} + +#else +int main(int, char**) { return 0;} +#endif diff --git a/libunwind/test/libunwind/__init__.py b/libunwind/test/libunwind/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libunwind/test/libunwind/test/__init__.py b/libunwind/test/libunwind/test/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libunwind/test/libunwind/test/config.py b/libunwind/test/libunwind/test/config.py new file mode 100644 index 0000000000..87a810b49d --- /dev/null +++ b/libunwind/test/libunwind/test/config.py @@ -0,0 +1,71 @@ +#===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===----------------------------------------------------------------------===## +import os +import sys + +from libcxx.test.config import Configuration as LibcxxConfiguration + + +class Configuration(LibcxxConfiguration): + # pylint: disable=redefined-outer-name + def __init__(self, lit_config, config): + super(Configuration, self).__init__(lit_config, config) + self.libunwind_src_root = None + self.libunwind_obj_root = None + self.abi_library_root = None + self.libcxx_src_root = None + + def configure_src_root(self): + self.libunwind_src_root = (self.get_lit_conf('libunwind_src_root') + or os.path.dirname(self.config.test_source_root)) + self.libcxx_src_root = (self.get_lit_conf('libcxx_src_root') + or os.path.join(self.libunwind_src_root, '..', 'libcxx')) + + def configure_obj_root(self): + self.libunwind_obj_root = self.get_lit_conf('libunwind_obj_root') + super(Configuration, self).configure_obj_root() + + def has_cpp_feature(self, feature, required_value): + return int(self.cxx.dumpMacros().get('__cpp_' + feature, 0)) >= required_value + + def configure_features(self): + super(Configuration, self).configure_features() + if self.get_lit_bool('arm_ehabi', False): + self.config.available_features.add('libunwind-arm-ehabi') + + def configure_compile_flags(self): + # Stack unwinding tests need unwinding tables and these are not + # generated by default on all Targets. + self.cxx.compile_flags += ['-funwind-tables'] + # Make symbols available in the tests. + triple = self.get_lit_conf('target_triple', None) + if triple is not None and 'linux' in triple: + self.cxx.link_flags += ['-Wl,--export-dynamic'] + if not self.get_lit_bool('enable_threads', True): + self.cxx.compile_flags += ['-D_LIBUNWIND_HAS_NO_THREADS'] + self.config.available_features.add('libunwind-no-threads') + if self.get_lit_bool('x86_cet', False): + self.cxx.compile_flags += ['-fcf-protection=full'] + super(Configuration, self).configure_compile_flags() + + def configure_compile_flags_header_includes(self): + libunwind_headers = self.get_lit_conf( + 'libunwind_headers', + os.path.join(self.libunwind_src_root, 'include')) + if not os.path.isdir(libunwind_headers): + self.lit_config.fatal("libunwind_headers='%s' is not a directory." + % libunwind_headers) + self.cxx.compile_flags += ['-I' + libunwind_headers] + + def configure_link_flags_cxx_library(self): + # libunwind tests should not link with libc++ + pass + + def configure_link_flags_abi_library(self): + # libunwind tests should not link with libc++abi + pass diff --git a/libunwind/test/libunwind_01.pass.cpp b/libunwind/test/libunwind_01.pass.cpp new file mode 100644 index 0000000000..aceb8bedf8 --- /dev/null +++ b/libunwind/test/libunwind_01.pass.cpp @@ -0,0 +1,147 @@ +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate these failures on x86_64 macOS +// XFAIL: target=x86_64-apple-darwin{{.+}} + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +#include +#include +#include + +void backtrace(int lower_bound) { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + int n = 0; + do { + ++n; + if (n > 100) { + abort(); + } + } while (unw_step(&cursor) > 0); + + if (n < lower_bound) { + abort(); + } +} + +void test1(int i) { + backtrace(i); +} + +void test2(int i, int j) { + backtrace(i); + test1(j); +} + +void test3(int i, int j, int k) { + backtrace(i); + test2(j, k); +} + +void test_no_info() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + unw_proc_info_t info; + int ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ESUCCESS) + abort(); + + // Set the IP to an address clearly outside any function. + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0); + + ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ENOINFO) + abort(); +} + +void test_reg_names() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + int max_reg_num = -100; +#if defined(__i386__) + max_reg_num = 7; +#elif defined(__x86_64__) + max_reg_num = 32; +#endif + + const char prefix[] = "unknown"; + for (int i = -2; i < max_reg_num; ++i) { + if (strncmp(prefix, unw_regname(&cursor, i), sizeof(prefix) - 1) == 0) + abort(); + } + + if (strncmp(prefix, unw_regname(&cursor, max_reg_num + 1), + sizeof(prefix) - 1) != 0) + abort(); +} + +#if defined(__x86_64__) +void test_reg_get_set() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + for (int i = 0; i < 17; ++i) { + const unw_word_t set_value = 7; + if (unw_set_reg(&cursor, i, set_value) != UNW_ESUCCESS) + abort(); + + unw_word_t get_value = 0; + if (unw_get_reg(&cursor, i, &get_value) != UNW_ESUCCESS) + abort(); + + if (set_value != get_value) + abort(); + } +} + +void test_fpreg_get_set() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + // get/set is not implemented for x86_64 fpregs. + for (int i = 17; i < 33; ++i) { + const unw_fpreg_t set_value = 7; + if (unw_set_fpreg(&cursor, i, set_value) != UNW_EBADREG) + abort(); + + unw_fpreg_t get_value = 0; + if (unw_get_fpreg(&cursor, i, &get_value) != UNW_EBADREG) + abort(); + } +} +#else +void test_reg_get_set() {} +void test_fpreg_get_set() {} +#endif + +int main(int, char**) { + test1(1); + test2(1, 2); + test3(1, 2, 3); + test_no_info(); + test_reg_names(); + test_reg_get_set(); + test_fpreg_get_set(); + return 0; +} diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp new file mode 100644 index 0000000000..64d8d58831 --- /dev/null +++ b/libunwind/test/libunwind_02.pass.cpp @@ -0,0 +1,45 @@ +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +#include +#include +#include + +#define EXPECTED_NUM_FRAMES 50 +#define NUM_FRAMES_UPPER_BOUND 100 + +_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) { + (void)context; + int *i = (int *)cnt; + ++*i; + if (*i > NUM_FRAMES_UPPER_BOUND) { + abort(); + } + return _URC_NO_REASON; +} + +void test_backtrace() { + int n = 0; + _Unwind_Backtrace(&callback, &n); + if (n < EXPECTED_NUM_FRAMES) { + abort(); + } +} + +int test(int i) { + if (i == 0) { + test_backtrace(); + return 0; + } else { + return i + test(i - 1); + } +} + +int main(int, char**) { + int total = test(50); + assert(total == 1275); + return 0; +} diff --git a/libunwind/test/lit.cfg.py b/libunwind/test/lit.cfg.py new file mode 100644 index 0000000000..647464abe2 --- /dev/null +++ b/libunwind/test/lit.cfg.py @@ -0,0 +1,10 @@ +# All the Lit configuration is handled in the site configs -- this file is only +# left as a canary to catch invocations of Lit that do not go through llvm-lit. +# +# Invocations that go through llvm-lit will automatically use the right Lit +# site configuration inside the build directory. + +lit_config.fatal( + "You seem to be running Lit directly -- you should be running Lit through " + "/bin/llvm-lit, which will ensure that the right Lit configuration " + "file is used.") diff --git a/libunwind/test/lit.site.cfg.in b/libunwind/test/lit.site.cfg.in new file mode 100644 index 0000000000..4fd633f877 --- /dev/null +++ b/libunwind/test/lit.site.cfg.in @@ -0,0 +1,58 @@ +@AUTO_GEN_COMMENT@ + +@SERIALIZED_LIT_PARAMS@ + +import os +import site + +config.cxx_under_test = "@CMAKE_CXX_COMPILER@" +config.project_obj_root = "@CMAKE_BINARY_DIR@" +config.install_root = "@CMAKE_BINARY_DIR@" +config.libunwind_src_root = "@LIBUNWIND_SOURCE_DIR@" +config.libunwind_obj_root = "@LIBUNWIND_BINARY_DIR@" +config.abi_library_root = "@LIBUNWIND_LIBRARY_DIR@" +config.libcxx_src_root = "@LIBUNWIND_LIBCXX_PATH@" +config.libunwind_headers = "@LIBUNWIND_SOURCE_DIR@/include" +config.cxx_library_root = "@LIBUNWIND_LIBCXX_LIBRARY_PATH@" +config.llvm_unwinder = True +config.builtins_library = "@LIBUNWIND_BUILTINS_LIBRARY@" +config.enable_threads = @LIBUNWIND_ENABLE_THREADS@ +config.target_info = "@LIBUNWIND_TARGET_INFO@" +config.test_linker_flags = "@LIBUNWIND_TEST_LINKER_FLAGS@" +config.test_compiler_flags = "@LIBUNWIND_TEST_COMPILER_FLAGS@" +config.executor = "@LIBUNWIND_EXECUTOR@" +config.libunwind_shared = @LIBUNWIND_ENABLE_SHARED@ +config.enable_shared = @LIBCXX_ENABLE_SHARED@ +config.arm_ehabi = @LIBUNWIND_USES_ARM_EHABI@ +config.host_triple = "@LLVM_HOST_TRIPLE@" +config.sysroot = "@LIBUNWIND_SYSROOT@" +config.gcc_toolchain = "@LIBUNWIND_GCC_TOOLCHAIN@" +config.cxx_ext_threads = @LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY@ +config.x86_cet = @LIBUNWIND_ENABLE_CET@ + +site.addsitedir(os.path.join(config.libunwind_src_root, 'test')) +site.addsitedir(os.path.join(config.libcxx_src_root, 'utils')) + +# name: The name of this test suite. +config.name = 'libunwind' + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = ['.cpp', '.s'] + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.join(config.libunwind_src_root, 'test') + +# Allow expanding substitutions that are based on other substitutions +config.recursiveExpansionLimit = 10 + +# Infer the test_exec_root from the build directory. +config.test_exec_root = os.path.join(config.libunwind_obj_root, 'test') + +import libcxx.test.format +config.test_format = libcxx.test.format.CxxStandardLibraryTest() + +lit_config.note('Using configuration variant: libunwind') +import libunwind.test.config +configuration = libunwind.test.config.Configuration(lit_config, config) +configuration.configure() +configuration.print_config_info() diff --git a/libunwind/test/remember_state_leak.pass.sh.s b/libunwind/test/remember_state_leak.pass.sh.s new file mode 100644 index 0000000000..fceac212c8 --- /dev/null +++ b/libunwind/test/remember_state_leak.pass.sh.s @@ -0,0 +1,65 @@ +# REQUIRES: target={{x86_64-.+-linux-gnu}} +# RUN: %{build} +# RUN: %{run} + +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +# TODO: Investigate this failure on GCC. +# XFAIL: gcc + +# The following assembly is a translation of this code: +# +# _Unwind_Reason_Code callback(int, _Unwind_Action, long unsigned int, +# _Unwind_Exception*, _Unwind_Context*, void*) { +# return _Unwind_Reason_Code(0); +# } +# +# int main() { +# asm(".cfi_remember_state\n\t"); +# _Unwind_Exception exc; +# _Unwind_ForcedUnwind(&exc, callback, 0); +# asm(".cfi_restore_state\n\t"); +# } +# +# When unwinding, the CFI parser will stop parsing opcodes after the current PC, +# so in this case the DW_CFA_restore_state opcode will never be processed and, +# if the library doesn't clean up properly, the store allocated by +# DW_CFA_remember_state will be leaked. +# +# This test will fail when linked with an asan-enabled libunwind if the +# remembered state is leaked. + + SIZEOF_UNWIND_EXCEPTION = 32 + + .text +callback: + xorl %eax, %eax + retq + + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc + subq $8, %rsp # Adjust stack alignment + subq $SIZEOF_UNWIND_EXCEPTION, %rsp + .cfi_def_cfa_offset 48 + .cfi_remember_state + movq %rsp, %rdi + movabsq $callback, %rsi + xorl %edx, %edx + callq _Unwind_ForcedUnwind + .cfi_restore_state + xorl %eax, %eax + addq $SIZEOF_UNWIND_EXCEPTION, %rsp + addq $8, %rsp # Undo stack alignment adjustment + .cfi_def_cfa_offset 8 + retq +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + # -- End function diff --git a/libunwind/test/signal_frame.pass.cpp b/libunwind/test/signal_frame.pass.cpp new file mode 100644 index 0000000000..fea189794b --- /dev/null +++ b/libunwind/test/signal_frame.pass.cpp @@ -0,0 +1,40 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that functions marked as signal frames are reported as such. + +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure on macOS +// XFAIL: target={{.+}}-apple-darwin{{.+}} + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +// UNSUPPORTED: libunwind-arm-ehabi + +#include +#include +#include + +void test() { + asm(".cfi_signal_frame"); + unw_cursor_t cursor; + unw_context_t uc; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + assert(unw_step(&cursor) > 0); + assert(unw_is_signal_frame(&cursor)); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libunwind/test/signal_unwind.pass.cpp b/libunwind/test/signal_unwind.pass.cpp new file mode 100644 index 0000000000..5468c7f672 --- /dev/null +++ b/libunwind/test/signal_unwind.pass.cpp @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that the unwinder can cope with the signal handler. +// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}}) + +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) { + (void)arg; + Dl_info info = { 0, 0, 0, 0 }; + + // Unwind util the main is reached, above frames depend on the platform and + // architecture. + if (dladdr(reinterpret_cast(_Unwind_GetIP(ctx)), &info) && + info.dli_sname && !strcmp("main", info.dli_sname)) { + _Exit(0); + } + return _URC_NO_REASON; +} + +void signal_handler(int signum) { + (void)signum; + _Unwind_Backtrace(frame_handler, NULL); + _Exit(-1); +} + +int main(int, char**) { + signal(SIGUSR1, signal_handler); + kill(getpid(), SIGUSR1); + return -2; +} diff --git a/libunwind/test/unw_getcontext.pass.cpp b/libunwind/test/unw_getcontext.pass.cpp new file mode 100644 index 0000000000..a02c8e5403 --- /dev/null +++ b/libunwind/test/unw_getcontext.pass.cpp @@ -0,0 +1,12 @@ +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +#include +#include + +int main(int, char**) { + unw_context_t context; + int ret = unw_getcontext(&context); + assert(ret == UNW_ESUCCESS); + return 0; +} diff --git a/libunwind/test/unwind_leaffunction.pass.cpp b/libunwind/test/unwind_leaffunction.pass.cpp new file mode 100644 index 0000000000..8fc343304c --- /dev/null +++ b/libunwind/test/unwind_leaffunction.pass.cpp @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that leaf function can be unwund. +// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}}) + +// TODO: Investigate these failures +// XFAIL: asan, tsan, ubsan + +// TODO: Investigate this failure +// XFAIL: 32bits-on-64bits + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) { + (void)arg; + Dl_info info = { 0, 0, 0, 0 }; + + // Unwind util the main is reached, above frames deeped on the platfrom and architecture. + if (dladdr(reinterpret_cast(_Unwind_GetIP(ctx)), &info) && + info.dli_sname && !strcmp("main", info.dli_sname)) { + _Exit(0); + } + return _URC_NO_REASON; +} + +void signal_handler(int signum) { + (void)signum; + _Unwind_Backtrace(frame_handler, NULL); + _Exit(-1); +} + +int* faultyPointer = NULL; + +__attribute__((noinline)) void crashing_leaf_func(void) { + *faultyPointer = 0; +} + +int main(int, char**) { + signal(SIGSEGV, signal_handler); + crashing_leaf_func(); + return -2; +} \ No newline at end of file From d94d864b2a769b2ff361d687361361c041675195 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 18 Oct 2021 18:21:37 +0200 Subject: [PATCH 067/478] feat: Build vendored libunwind (NATIVE-274) (#53) This builds the vendored copy of libunwind on macOS when CRASHPAD_ENABLE_STACKTRACE is enabled. Co-authored-by: Sebastian Zivota --- CMakeLists.txt | 5 +++++ libunwind/CMakeLists.txt | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d7a479540..b7863dff9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,11 @@ add_subdirectory(third_party/getopt) add_subdirectory(tools) add_subdirectory(handler) +if(CRASHPAD_ENABLE_STACKTRACE AND APPLE AND NOT IOS) + set(LIBUNWIND_ENABLE_SHARED OFF) + add_subdirectory(libunwind) +endif() + if(CRASHPAD_ENABLE_INSTALL_DEV) install(EXPORT crashpad_export NAMESPACE crashpad:: FILE crashpad-targets.cmake DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index 9b55195b83..ec0049ddb5 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -1,7 +1,3 @@ -if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libcxx") - message(FATAL_ERROR "libunwind requires being built in a monorepo layout with libcxx available") -endif() - #=============================================================================== # Setup Project #=============================================================================== From 897bad95e7307908fc3aa744df9f504f8f564533 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 19 Oct 2021 12:36:06 +0200 Subject: [PATCH 068/478] feat: Do client-side stackwalking on Linux (NATIVE-152) (#49) Co-authored-by: Betty Da Co-authored-by: Arpad Borsos --- .github/workflows/build.yml | 2 +- snapshot/CMakeLists.txt | 6 +++ snapshot/linux/process_snapshot_linux.cc | 5 +++ snapshot/linux/thread_snapshot_linux.cc | 52 ++++++++++++++++++++++++ snapshot/linux/thread_snapshot_linux.h | 4 ++ 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ce12943427..cbefe8feaa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: if: ${{ runner.os == 'Linux' }} run: | sudo apt update - sudo apt install zlib1g-dev libcurl4-openssl-dev libssl-dev libunwind-dev + sudo apt install zlib1g-dev libcurl4-openssl-dev libssl-dev libunwind-dev pkg-config - name: Build crashpad run: | diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index c684793993..8b3d9fd850 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -224,6 +224,12 @@ if(WIN32) endif() endif() +if(LINUX AND CRASHPAD_ENABLE_STACKTRACE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(UNWIND REQUIRED IMPORTED_TARGET libunwind-ptrace) + target_link_libraries(crashpad_snapshot PRIVATE PkgConfig::UNWIND) +endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(crashpad_snapshot PRIVATE "-Wno-multichar" diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 35f870ec76..affa46cd0b 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -104,6 +104,11 @@ bool ProcessSnapshotLinux::InitializeException( return false; } +#ifdef CLIENT_STACKTRACES_ENABLED + exc_thread_snapshot->TrimStackTrace( + exception_->Context()->InstructionPointer()); +#endif + for (auto& thread_snapshot : threads_) { if (thread_snapshot->ThreadID() == static_cast(info.thread_id)) { diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc index e3e2bebddb..b9d889e757 100644 --- a/snapshot/linux/thread_snapshot_linux.cc +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -16,6 +16,12 @@ #include +#ifdef CLIENT_STACKTRACES_ENABLED +#include +#include +#include +#endif + #include "base/logging.h" #include "snapshot/linux/cpu_context_linux.h" #include "util/misc/reinterpret_bytes.h" @@ -199,6 +205,37 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, thread_id_ = thread.tid; +#ifdef CLIENT_STACKTRACES_ENABLED + void* upt = _UPT_create(thread_id_); + if (upt) { + unw_addr_space_t as = + unw_create_addr_space(&_UPT_accessors, __LITTLE_ENDIAN); + unw_cursor_t cursor; + if (unw_init_remote(&cursor, as, upt) == UNW_ESUCCESS) { + do { + unw_word_t addr; + if (unw_get_reg(&cursor, UNW_REG_IP, &addr) < 0) { + return false; + } + + std::string sym(""); + char buf[1024]; + unw_word_t symbol_offset; + if (unw_get_proc_name(&cursor, buf, sizeof(buf), &symbol_offset) == + UNW_ESUCCESS) { + sym = std::string(buf); + } + + FrameSnapshot frame(addr, sym); + frames_.push_back(frame); + } while (unw_step(&cursor) > 0); + } + + unw_destroy_addr_space(as); + _UPT_destroy(upt); + } +#endif + priority_ = thread.have_priorities ? ComputeThreadPriority( @@ -243,5 +280,20 @@ std::vector ThreadSnapshotLinux::ExtraMemory() const { return std::vector(); } +#ifdef CLIENT_STACKTRACES_ENABLED +void ThreadSnapshotLinux::TrimStackTrace(uint64_t exception_address) { + auto start_frame = begin(frames_); + for (; start_frame != end(frames_); start_frame++) { + // These two addresses are never equivalent to each other + if (start_frame->InstructionAddr() == exception_address) { + break; + } + } + if (start_frame < end(frames_)) { + frames_.erase(begin(frames_), start_frame); + } +} +#endif + } // namespace internal } // namespace crashpad diff --git a/snapshot/linux/thread_snapshot_linux.h b/snapshot/linux/thread_snapshot_linux.h index 44cc6f6d97..0d84eeade5 100644 --- a/snapshot/linux/thread_snapshot_linux.h +++ b/snapshot/linux/thread_snapshot_linux.h @@ -57,6 +57,10 @@ class ThreadSnapshotLinux final : public ThreadSnapshot { uint64_t ThreadSpecificDataAddress() const override; std::vector ExtraMemory() const override; +#ifdef CLIENT_STACKTRACES_ENABLED + void TrimStackTrace(uint64_t exception_address); +#endif + private: union { #if defined(ARCH_CPU_X86_FAMILY) From b0677d2ae96a7943789c3c4850ef0f6af2778c2f Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 19 Oct 2021 12:37:01 +0200 Subject: [PATCH 069/478] feat: Add remote unwinding to libunwind (NATIVE-151) (#52) This patches our vendored libunwind version to support remote unwinding on macOS. More specifically, this revives some previously existing, but never finished or working code, which was removed in https://github.com/llvm/llvm-project/commit/368c02e3ec44e5418626f46abebcc22a69c7f66d --- libunwind/include/libunwind.h | 10 + libunwind/src/AddressSpace.hpp | 442 ++++++++++++++++++++++++++++++ libunwind/src/CompactUnwinder.hpp | 26 ++ libunwind/src/UnwindCursor.hpp | 31 ++- libunwind/src/libunwind.cpp | 37 +++ 5 files changed, 541 insertions(+), 5 deletions(-) diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h index 5ba63e5b7e..019fa9a767 100644 --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -19,6 +19,9 @@ #include #ifdef __APPLE__ + + #include + #if __clang__ #if __has_include() #include @@ -130,6 +133,13 @@ extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUN extern unw_addr_space_t unw_local_addr_space; +/* + * Mac OS X "remote" API for unwinding other processes on same machine + */ +extern unw_addr_space_t unw_create_addr_space_for_task(task_t); +extern void unw_destroy_addr_space(unw_addr_space_t); +extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t); + #ifdef __cplusplus } #endif diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 171318ff63..e856f64164 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -47,6 +47,12 @@ struct EHABIIndexEntry { #ifdef __APPLE__ + #include + #include + #include + #include + #include + struct dyld_unwind_sections { const struct mach_header* mh; @@ -625,6 +631,442 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, return false; } +struct found_mach_info { + struct mach_header_64 header; + struct segment_command_64 segment; + uintptr_t ptr_after_segment; + uintptr_t load_addr; + uintptr_t slide; + uintptr_t text_size; + bool header_valid; + bool segment_valid; +}; + +/// RemoteAddressSpace is used as a template parameter to UnwindCursor when +/// unwinding a thread in the another process. +/// In theory, the other process can be a different endianness and a different +/// pointer size which was handled by the P template parameter in the original +/// implementation. +/// However, we assume that we are only dealing with x64 and arm64 here, which +/// have both the same endianness and pointer size. +class RemoteAddressSpace { +public: + RemoteAddressSpace(task_t task) : task_(task), last_found_image(found_mach_info()) {} + static void *operator new(size_t, RemoteAddressSpace *p) { return p; } + + typedef uintptr_t pint_t; + typedef intptr_t sint_t; + uint8_t get8(pint_t addr) { + uint8_t val = 0; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + uint16_t get16(pint_t addr) { + uint16_t val = 0; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + uint32_t get32(pint_t addr) { + uint32_t val = 0; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + uint64_t get64(pint_t addr) { + uint64_t val = 0; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + double getDouble(pint_t addr) { + double val = 0; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + v128 getVector(pint_t addr) { + v128 val = {0}; + memcpy_from_remote(&val, (void *)addr, sizeof(val)); + return val; + } + + uintptr_t getP(pint_t addr) { + return get64(addr); + } + uint64_t getRegister(pint_t addr) { + return get64(addr); + } + + uint64_t getULEB128(pint_t &addr, pint_t end); + int64_t getSLEB128(pint_t &addr, pint_t end); + + pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase = 0); + bool findFunctionName(pint_t addr, char *buf, size_t bufLen, + unw_word_t *offset); + bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); + bool findOtherFDE(pint_t targetAddr, pint_t &fde); + +private: + kern_return_t memcpy_from_remote(void *dest, void *src, size_t size); + + // Finds the mach image that contains `targetAddr`, and saves it and the + // corresponding `segment` in the local `last_found_image`, returning `true` + // on success. + bool findMachSegment(pint_t targetAddr, const char *segment); + // Similar to the above, except it assumes the `header` of `last_found_image` + // is valid. + bool findMachSegmentInImage(pint_t targetAddr, const char *segment); + + task_t task_; + found_mach_info last_found_image; +}; + +uint64_t RemoteAddressSpace::getULEB128(pint_t &addr, pint_t end) { + uintptr_t size = (end - addr); + char buf[16] = {0}; + memcpy_from_remote(buf, (void *)addr, 16); + LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)buf; + LocalAddressSpace::pint_t sladdr = laddr; + uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); + addr += (laddr - sladdr); + return result; +} + +int64_t RemoteAddressSpace::getSLEB128(pint_t &addr, pint_t end) { + uintptr_t size = (end - addr); + char buf[16] = {0}; + memcpy_from_remote(buf, (void *)addr, 16); + LocalAddressSpace::pint_t laddr = + (LocalAddressSpace::pint_t)buf; + LocalAddressSpace::pint_t sladdr = laddr; + int64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); + addr += (laddr - sladdr); + return result; +} + +kern_return_t RemoteAddressSpace::memcpy_from_remote(void *dest, void *src, size_t size) { + size_t read_bytes = 0; + kern_return_t kr = mach_vm_read_overwrite( + task_, (mach_vm_address_t)src, (mach_vm_size_t)size, + (mach_vm_address_t)dest, (mach_vm_size_t *)&read_bytes); + return kr; +} + +// we needed to copy this whole function since we can’t reuse the one from +// `LocalAddressSpace`. :-( +RemoteAddressSpace::pint_t +RemoteAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, + pint_t datarelBase) { + pint_t startAddr = addr; + const uint8_t *p = (uint8_t *)addr; + pint_t result; + + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_ptr: + result = getP(addr); + p += sizeof(pint_t); + addr = (pint_t)p; + break; + case DW_EH_PE_uleb128: + result = (pint_t)getULEB128(addr, end); + break; + case DW_EH_PE_udata2: + result = get16(addr); + p += 2; + addr = (pint_t)p; + break; + case DW_EH_PE_udata4: + result = get32(addr); + p += 4; + addr = (pint_t)p; + break; + case DW_EH_PE_udata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t)p; + break; + case DW_EH_PE_sleb128: + result = (pint_t)getSLEB128(addr, end); + break; + case DW_EH_PE_sdata2: + // Sign extend from signed 16-bit value. + result = (pint_t)(int16_t)get16(addr); + p += 2; + addr = (pint_t)p; + break; + case DW_EH_PE_sdata4: + // Sign extend from signed 32-bit value. + result = (pint_t)(int32_t)get32(addr); + p += 4; + addr = (pint_t)p; + break; + case DW_EH_PE_sdata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t)p; + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + } + + // then add relative offset + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + result += startAddr; + break; + case DW_EH_PE_textrel: + _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); + break; + case DW_EH_PE_datarel: + // DW_EH_PE_datarel is only valid in a few places, so the parameter has a + // default value of 0, and we abort in the event that someone calls this + // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. + if (datarelBase == 0) + _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); + result += datarelBase; + break; + case DW_EH_PE_funcrel: + _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); + break; + case DW_EH_PE_aligned: + _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + break; + } + + if (encoding & DW_EH_PE_indirect) + result = getP(result); + + return result; +} + +bool RemoteAddressSpace::findMachSegment(pint_t targetAddr, + const char *segment) { + if (!last_found_image.header_valid || !(last_found_image.load_addr <= targetAddr && last_found_image.load_addr + last_found_image.text_size > targetAddr)) { + last_found_image.segment_valid = false; + // enumerate all images and find the one we are looking for. + + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(task_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, + &count) != KERN_SUCCESS) { + return false; + } + if (task_dyld_info.all_image_info_format != TASK_DYLD_ALL_IMAGE_INFO_64) { + return false; + } + + dyld_all_image_infos all_images_info; + if (memcpy_from_remote(&all_images_info, + (void *)task_dyld_info.all_image_info_addr, + sizeof(dyld_all_image_infos)) != KERN_SUCCESS) { + return false; + }; + + for (size_t i = 0; i < all_images_info.infoArrayCount; i++) { + dyld_image_info image; + if (memcpy_from_remote(&image, (void *)&all_images_info.infoArray[i], + sizeof(dyld_image_info)) != KERN_SUCCESS) { + continue; + }; + + // image is out of range of `targetAddr` + if ((pint_t)image.imageLoadAddress > targetAddr) { + continue; + } + + if (memcpy_from_remote(&last_found_image.header, + (void *)image.imageLoadAddress, + sizeof(struct mach_header_64)) != KERN_SUCCESS) { + continue; + }; + + if (last_found_image.header.magic != MH_MAGIC_64) { + continue; + } + + last_found_image.load_addr = (size_t)image.imageLoadAddress; + if (findMachSegmentInImage(targetAddr, "__TEXT")) { + last_found_image.header_valid = true; + break; + } + } + } + + if (!last_found_image.header_valid) { + return false; + } + + if (!last_found_image.segment_valid || + strcmp(last_found_image.segment.segname, segment) != 0) { + // search for the segment in the image + if (!findMachSegmentInImage(targetAddr, segment)) { + return false; + } + } + return true; +} + +bool RemoteAddressSpace::findMachSegmentInImage(pint_t targetAddr, const char*segment) { + // This section here is basically a remote-rewrite of + // `dyld_exceptions_init` from: + // https://opensource.apple.com/source/dyld/dyld-195.6/src/dyldExceptions.c.auto.html + struct load_command cmd; + pint_t cmd_ptr = + (pint_t)last_found_image.load_addr + sizeof(struct mach_header_64); + bool found_text = false; + bool found_searched = false; + for (size_t c = 0; c < last_found_image.header.ncmds; c++) { + if (memcpy_from_remote(&cmd, (void *)cmd_ptr, + sizeof(struct load_command)) != KERN_SUCCESS) { + return false; + }; + if (cmd.cmd == LC_SEGMENT_64) { + struct segment_command_64 seg; + if (memcpy_from_remote(&seg, (void *)cmd_ptr, + sizeof(struct segment_command_64)) != + KERN_SUCCESS) { + return false; + }; + + if (strcmp(seg.segname, "__TEXT") == 0) { + pint_t slide = last_found_image.load_addr - seg.vmaddr; + + // text section out of range of `targetAddr` + pint_t text_end = seg.vmaddr + seg.vmsize + slide; + if (text_end < targetAddr) { + return false; + } + last_found_image.slide = slide; + last_found_image.text_size = seg.vmsize; + found_text = true; + } + if (strncmp(seg.segname, segment, 16) == 0) { + pint_t sect_ptr = cmd_ptr + sizeof(struct segment_command_64); + last_found_image.segment_valid = true; + last_found_image.segment = seg; + last_found_image.ptr_after_segment = sect_ptr; + found_searched = true; + } + if (found_text && found_searched) { + return true; + } + } + cmd_ptr += cmd.cmdsize; + } + return false; +} + +inline bool RemoteAddressSpace::findUnwindSections(pint_t targetAddr, + UnwindInfoSections &info) { + if (!findMachSegment(targetAddr, "__TEXT")) { + return false; + } + + info.dso_base = last_found_image.load_addr; + info.dwarf_section = 0; + info.compact_unwind_section = 0; + + for (size_t s = 0; s < last_found_image.segment.nsects; s++) { + struct section_64 sect; + if (memcpy_from_remote(§, + (void *)(last_found_image.ptr_after_segment + + s * sizeof(struct section_64)), + sizeof(struct section_64)) != KERN_SUCCESS) { + continue; + }; + + if (strcmp(sect.sectname, "__eh_frame") == 0) { + info.dwarf_section = sect.addr + last_found_image.slide; + info.dwarf_section_length = sect.size; + } else if (strcmp(sect.sectname, "__unwind_info") == 0) { + info.compact_unwind_section = sect.addr + last_found_image.slide; + info.compact_unwind_section_length = sect.size; + } + } + return true; +} + +bool RemoteAddressSpace::findOtherFDE(pint_t targetAddr, pint_t & fde) { + // TO DO: if OS has way to dynamically register FDEs, check that. + (void)targetAddr; + (void)fde; + return false; +} + +bool RemoteAddressSpace::findFunctionName(pint_t addr, char *buf, + size_t bufLen, unw_word_t *offset) { + // This is essentially a remote re-implementation of this snippet: + // https://gist.github.com/integeruser/b0d3ea6c4e8387d036acf6c77c0ec406 + + if (!findMachSegment(addr, "__TEXT")) { + return false; + } + + struct load_command cmd; + pint_t cmd_ptr = + (pint_t)last_found_image.load_addr + sizeof(struct mach_header_64); + for (size_t c = 0; c < last_found_image.header.ncmds; c++) { + if (memcpy_from_remote(&cmd, (void *)cmd_ptr, + sizeof(struct load_command)) != KERN_SUCCESS) { + return false; + }; + + if (cmd.cmd == LC_SYMTAB) { + struct symtab_command seg; + if (memcpy_from_remote(&seg, (void *)cmd_ptr, + sizeof(struct symtab_command)) != KERN_SUCCESS) { + return false; + }; + + pint_t strtab = last_found_image.load_addr + seg.stroff; + pint_t nearest_sym = 0; + for (size_t s = 0; s < seg.nsyms; s++) { + struct nlist_64 nlist; + if (memcpy_from_remote(&nlist, + (void *)(last_found_image.load_addr + + seg.symoff + + s * sizeof(struct nlist_64)), + sizeof(struct nlist_64)) != KERN_SUCCESS) { + return false; + }; + + if ((nlist.n_type & N_STAB) != 0 || (nlist.n_type & N_TYPE) != N_SECT || + nlist.n_un.n_strx == 0) { + continue; + } + + pint_t sym_addr = nlist.n_value + last_found_image.slide; + if (sym_addr > nearest_sym && sym_addr < addr) { + pint_t symbol_start = strtab + nlist.n_un.n_strx; + pint_t bytes_to_copy = strtab + seg.strsize - symbol_start; + if (bytes_to_copy > bufLen) { + bytes_to_copy = bufLen; + } + if (memcpy_from_remote(buf, (void *)(symbol_start), bytes_to_copy) != + KERN_SUCCESS) { + return false; + } + buf[bufLen - 1] = '\0'; + nearest_sym = sym_addr; + } + } + if (nearest_sym > 0) { + return true; + } + break; + } + cmd_ptr += cmd.cmdsize; + } + + (void)offset; + return false; +} + } // namespace libunwind #endif // __ADDRESSSPACE_HPP__ diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp index 312bfbb2c7..369079ae60 100644 --- a/libunwind/src/CompactUnwinder.hpp +++ b/libunwind/src/CompactUnwinder.hpp @@ -274,6 +274,8 @@ class CompactUnwinder_x86_64 { static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, Registers_x86_64 ®isters); + static int stepSpeculatively( + A &addressSpace, Registers_x86_64 ®isters); static int stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, @@ -288,6 +290,8 @@ int CompactUnwinder_x86_64::stepWithCompactEncoding( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_x86_64 ®isters) { switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { + case 0: + return stepSpeculatively(addressSpace, registers); case UNWIND_X86_64_MODE_RBP_FRAME: return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, addressSpace, registers); @@ -301,6 +305,28 @@ int CompactUnwinder_x86_64::stepWithCompactEncoding( _LIBUNWIND_ABORT("invalid compact unwind encoding"); } +template +int CompactUnwinder_x86_64::stepSpeculatively( + A &addressSpace, Registers_x86_64 ®isters) { + uint64_t rsp = registers.getSP(); + uint64_t rbp = registers.getRBP(); + if (rsp == rbp) { + // In this case we assume this was a standard `push rbp, rbp = rsp` + // preamble, so the stack should only have the old rbp, and the return + // address on it. This is the case in, for example: + // - `libsystem_platform.dylib/_platform_bzero$VARIANT$Haswell` + frameUnwind(addressSpace, registers); + } else { + // Here, we assume that the function has no stack space of its own, so we + // assume the return address is right there at the top. This happens for + // for example in: + // - `libsystem_kernel.dylib/__psynch_cvwait` + // - and other functions which appear to be syscall wrappers + framelessUnwind(addressSpace, rsp, registers); + } + return UNW_STEP_SUCCESS; +} + template int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 7157fa92bf..dd193856a8 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -23,6 +23,7 @@ #endif #ifdef __APPLE__ #include + #include #endif #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) @@ -889,7 +890,7 @@ class UnwindCursor : public AbstractUnwindCursor{ typedef typename A::pint_t pint_t; public: UnwindCursor(unw_context_t *context, A &as); - UnwindCursor(A &as, void *threadArg); + UnwindCursor(A &as, thread_t thread); virtual ~UnwindCursor() {} virtual bool validReg(int); virtual unw_word_t getReg(int); @@ -1226,13 +1227,31 @@ UnwindCursor::UnwindCursor(unw_context_t *context, A &as) } template -UnwindCursor::UnwindCursor(A &as, void *) +UnwindCursor::UnwindCursor(A &as, thread_t thread) : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { memset(&_info, 0, sizeof(_info)); - // FIXME - // fill in _registers from thread arg -} +#if defined(__x86_64__) + thread_state_flavor_t thread_state_flavor = x86_THREAD_STATE64; + mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; +#elif defined(__aarch64__) + thread_state_flavor_t thread_state_flavor = ARM_THREAD_STATE64; + mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT; +#else +#error Architecture not supported +#endif + + // lucky us: the layout of the various `Registers_X` classes matches whatever + // the mach kernel is writing here. + + kern_return_t kr = + thread_get_state(thread, thread_state_flavor, + (thread_state_t)&_registers, + &thread_state_count); + + // FIXME: the function is infallible + (void)kr; +} template bool UnwindCursor::validReg(int regNum) { @@ -1951,8 +1970,10 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #endif // If unwind table has entry, but entry says there is no unwind info, // record that we have no unwind info. +#ifndef _LIBUNWIND_TARGET_X86_64 if (_info.format == 0) _unwindInfoMissing = true; +#endif return; } } diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp index 93e1bc131f..fffffa76dd 100644 --- a/libunwind/src/libunwind.cpp +++ b/libunwind/src/libunwind.cpp @@ -88,6 +88,43 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, } _LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local) +/// Create a cursor into a thread in another process. +_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, + unw_addr_space_t as, thread_t thread) { +#if defined(__x86_64__) +# define REGISTER_KIND Registers_x86_64 +#elif defined(__aarch64__) +# define REGISTER_KIND Registers_arm64 +#else +# error Architecture not supported +#endif + // Use "placement new" to allocate UnwindCursor in the cursor buffer. + new (reinterpret_cast *>( + cursor)) + UnwindCursor(*(RemoteAddressSpace*)as, + thread); +#undef REGISTER_KIND + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->setInfoBasedOnIPRegister(); + + return UNW_ESUCCESS; +} + +/// Create an address_space object for use in examining another task. +_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { + RemoteAddressSpace *as = + (RemoteAddressSpace *)malloc(sizeof(RemoteAddressSpace)); + new (as) RemoteAddressSpace(task); + return (unw_addr_space_t)as; +} + +/// Delete an address_space object. +_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { + RemoteAddressSpace *as = (RemoteAddressSpace *)asp; + as->~RemoteAddressSpace(); + free(as); +} + /// Get value of specified register at cursor position in stack frame. _LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, unw_word_t *value) { From e4719db8283fa1fe17047fe921422c2ab5319c1c Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 19 Oct 2021 14:23:53 +0200 Subject: [PATCH 070/478] feat: Do client-side stackwalking on Mac (NATIVE-151) (#47) --- CMakeLists.txt | 1 + snapshot/CMakeLists.txt | 12 ++++++--- snapshot/mac/process_reader_mac.h | 3 ++- snapshot/mac/thread_snapshot_mac.cc | 39 ++++++++++++++++++++++++++--- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7863dff9d..de1a504ac6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ add_subdirectory(handler) if(CRASHPAD_ENABLE_STACKTRACE AND APPLE AND NOT IOS) set(LIBUNWIND_ENABLE_SHARED OFF) add_subdirectory(libunwind) + crashpad_install_target(unwind_static) endif() if(CRASHPAD_ENABLE_INSTALL_DEV) diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 8b3d9fd850..9d607e401a 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -46,7 +46,6 @@ add_library(crashpad_snapshot STATIC unloaded_module_snapshot.h ) - if(APPLE AND NOT IOS) target_sources(crashpad_snapshot PRIVATE posix/timezone.cc @@ -224,10 +223,15 @@ if(WIN32) endif() endif() +if(APPLE AND NOT IOS AND CRASHPAD_ENABLE_STACKTRACE) + target_include_directories(crashpad_snapshot PRIVATE ../libunwind/include) + target_link_libraries(crashpad_snapshot PRIVATE unwind_static) +endif() + if(LINUX AND CRASHPAD_ENABLE_STACKTRACE) - find_package(PkgConfig REQUIRED) - pkg_check_modules(UNWIND REQUIRED IMPORTED_TARGET libunwind-ptrace) - target_link_libraries(crashpad_snapshot PRIVATE PkgConfig::UNWIND) + find_package(PkgConfig REQUIRED) + pkg_check_modules(UNWIND REQUIRED IMPORTED_TARGET libunwind-ptrace) + target_link_libraries(crashpad_snapshot PRIVATE PkgConfig::UNWIND) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h index 2f8ea9dcec..a462d1d144 100644 --- a/snapshot/mac/process_reader_mac.h +++ b/snapshot/mac/process_reader_mac.h @@ -181,6 +181,8 @@ class ProcessReaderMac { //! On failure, returns `0` with a message logged. mach_vm_address_t DyldAllImageInfo(mach_vm_size_t* all_image_info_size); + task_t task_; // weak + private: //! Performs lazy initialization of the \a threads_ vector on behalf of //! Threads(). @@ -250,7 +252,6 @@ class ProcessReaderMac { std::vector modules_; std::vector> module_readers_; ProcessMemoryMac process_memory_; - task_t task_; // weak InitializationStateDcheck initialized_; #if defined(CRASHPAD_MAC_32_BIT_SUPPORT) diff --git a/snapshot/mac/thread_snapshot_mac.cc b/snapshot/mac/thread_snapshot_mac.cc index d261f194ad..7ae5f9fae4 100644 --- a/snapshot/mac/thread_snapshot_mac.cc +++ b/snapshot/mac/thread_snapshot_mac.cc @@ -18,6 +18,10 @@ #include "snapshot/mac/cpu_context_mac.h" #include "snapshot/mac/process_reader_mac.h" +#ifdef CLIENT_STACKTRACES_ENABLED +#include +#endif + namespace crashpad { namespace internal { @@ -31,11 +35,9 @@ ThreadSnapshotMac::ThreadSnapshotMac() thread_(MACH_PORT_NULL), suspend_count_(0), priority_(0), - initialized_() { -} + initialized_() {} -ThreadSnapshotMac::~ThreadSnapshotMac() { -} +ThreadSnapshotMac::~ThreadSnapshotMac() {} bool ThreadSnapshotMac::Initialize( ProcessReaderMac* process_reader, @@ -89,6 +91,35 @@ bool ThreadSnapshotMac::Initialize( #error Port to your CPU architecture #endif +#ifdef CLIENT_STACKTRACES_ENABLED + unw_addr_space_t as = unw_create_addr_space_for_task(process_reader->task_); + unw_cursor_t cursor; + + if (unw_init_remote_thread(&cursor, as, thread_) == UNW_ESUCCESS) { + do { + unw_word_t addr; + unw_get_reg(&cursor, UNW_REG_IP, &addr); + + std::string sym(""); + char buf[1024]; + unw_word_t symbol_offset; + if (unw_get_proc_name(&cursor, buf, sizeof(buf), &symbol_offset) == + UNW_ESUCCESS) { + if (buf[0] == '_') { + sym = std::string(buf + 1); + } else { + sym = std::string(buf); + } + } + + FrameSnapshot frame(addr, sym); + frames_.push_back(frame); + } while (unw_step(&cursor) > 0); + } + + unw_destroy_addr_space(as); +#endif + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } From bc22a7b09ca881ab5fb2ada5720268d1e98f2857 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Fri, 29 Oct 2021 13:04:08 +0200 Subject: [PATCH 071/478] feat: Clientside stacktraces for ARM64 [NATIVE-289] (#54) The changes that were needed to make this work: * strip the pointer-authentication code from instruction addresses we read do speculative link-register or frame-pointer based unwinding if we have a 0 compact encoding. Co-authored-by: Jan Michael Auer Co-authored-by: Arpad Borsos Co-authored-by: Arpad Borsos --- libunwind/src/CompactUnwinder.hpp | 76 ++++++++++++++++++++++++++++--- libunwind/src/UnwindCursor.hpp | 6 +-- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp index 369079ae60..bcf0424474 100644 --- a/libunwind/src/CompactUnwinder.hpp +++ b/libunwind/src/CompactUnwinder.hpp @@ -516,6 +516,13 @@ void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, #if defined(_LIBUNWIND_TARGET_AARCH64) +uint64_t strip_ptr_auth(uint64_t pointer) { + // mask is taken from: + // https://github.com/dotnet/runtime/pull/40435/files/af4db134ddd9deea10e75d3f732cc35d3b61119e#r479544995 + uint64_t mask = 0x7fffffffffffull; + return pointer & mask; +} + /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka /// unwind) by modifying a Registers_arm64 register set template @@ -529,6 +536,8 @@ class CompactUnwinder_arm64 { private: typename A::pint_t pint_t; + static int stepSpeculatively( + A &addressSpace, Registers_arm64 ®isters); static int stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, @@ -542,17 +551,72 @@ template int CompactUnwinder_arm64::stepWithCompactEncoding( compact_unwind_encoding_t compactEncoding, uint64_t functionStart, A &addressSpace, Registers_arm64 ®isters) { + int result = 0; switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { + case 0: + result = stepSpeculatively(addressSpace, registers); + registers.setRegister(UNW_AARCH64_LR, 0); + return result; case UNWIND_ARM64_MODE_FRAME: - return stepWithCompactEncodingFrame(compactEncoding, functionStart, - addressSpace, registers); + result = stepWithCompactEncodingFrame(compactEncoding, functionStart, + addressSpace, registers); + registers.setRegister(UNW_AARCH64_LR, 0); + return result; case UNWIND_ARM64_MODE_FRAMELESS: - return stepWithCompactEncodingFrameless(compactEncoding, functionStart, - addressSpace, registers); + result = stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers); + registers.setRegister(UNW_AARCH64_LR, 0); + return result; } _LIBUNWIND_ABORT("invalid compact unwind encoding"); } +template +int CompactUnwinder_arm64::stepSpeculatively( + A &addressSpace, Registers_arm64 ®isters) { + // XXX: breakpad sets the IP from the LR, which is only correct if we do + // framepointer unwinding all the way. + // However, compact unwinding code never actually restores the LR, so we + // might have some bogus values in this case. We could do that at the bottom + // of `stepWithCompactEncodingFrame` but that wouldn't really solve the + // problem, as that is also a duplicated/bogus LR then. Long story short, + // what this means is, that we use the LR (correctly) when we are missing + // compact unwind info for the *first* frame. We are lucky though, as it + // is mostly the top frames which are missing unwind info + // (they are what appears to be syscall wrappers mostly). + // To overcome this, we use the LR only if we are at the first frame. + // (we reset it to 0 after a `step` call) + // All other frames use frame-pointer based unwinding, fetching the return + // address from the stack. + + uint64_t lr = strip_ptr_auth(registers.getRegister(UNW_AARCH64_LR)); + + if (lr) { + registers.setIP(lr); + } else { + // this is a recreation of: + // https://github.com/getsentry/breakpad/blob/master/src/processor/stackwalker_arm64.cc#L208-L252 + uint64_t last_fp = registers.getFP(); + uint64_t caller_fp = 0; + uint64_t caller_lr = 0; + uint64_t caller_sp = registers.getSP(); + + if (last_fp) { + // fp points to old fp + caller_fp = addressSpace.get64(last_fp); + // old sp is fp less saved fp and lr + caller_sp = last_fp + 16; + // pop return address into pc + caller_lr = strip_ptr_auth(addressSpace.get64(last_fp + 8)); + } + + registers.setFP(caller_fp); + registers.setSP(caller_sp); + registers.setIP(caller_lr); + } + return UNW_STEP_SUCCESS; +} + template int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, @@ -630,7 +694,7 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( registers.setSP(savedRegisterLoc); // set pc to be value in lr - registers.setIP(registers.getRegister(UNW_AARCH64_LR)); + registers.setIP(strip_ptr_auth(registers.getRegister(UNW_AARCH64_LR))); return UNW_STEP_SUCCESS; } @@ -711,7 +775,7 @@ int CompactUnwinder_arm64::stepWithCompactEncodingFrame( // old sp is fp less saved fp and lr registers.setSP(fp + 16); // pop return address into pc - registers.setIP(addressSpace.get64(fp + 8)); + registers.setIP(strip_ptr_auth(addressSpace.get64(fp + 8))); return UNW_STEP_SUCCESS; } diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index dd193856a8..f8dd3f272e 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1970,10 +1970,8 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { #endif // If unwind table has entry, but entry says there is no unwind info, // record that we have no unwind info. -#ifndef _LIBUNWIND_TARGET_X86_64 - if (_info.format == 0) - _unwindInfoMissing = true; -#endif + // if (_info.format == 0) + // _unwindInfoMissing = true; return; } } From 23fe39510a3c2edc537d4b17805809be5dcf64df Mon Sep 17 00:00:00 2001 From: walterbrebels Date: Tue, 23 Nov 2021 11:42:48 +0100 Subject: [PATCH 072/478] build: Don't add /Zi to compiler flags with MSVC (#56) --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de1a504ac6..e228933505 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,7 +92,6 @@ if(MSVC) $<$:/FS> $<$:/W4> $<$:/WX> - $<$:/Zi> $<$:/bigobj> # Support larger number of sections in obj file. $<$:/wd4100> # Unreferenced formal parameter. $<$:/wd4127> # Conditional expression is constant. From b9ff9fd3e237cf6ef930f01f1732b7d12c0316e6 Mon Sep 17 00:00:00 2001 From: Siim Meerits Date: Wed, 24 Nov 2021 10:17:05 +0200 Subject: [PATCH 073/478] msvc: Install getopt target and link crashpad handler library with getopt. (#55) The 'crashpad_handler' library uses getopt functionality in 'HandlerMain' function. Hence when implementing your own crash handler instead of using bundled handler program the getopt library needs to be linked in as well. --- handler/CMakeLists.txt | 1 + third_party/getopt/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 75f8bbb41e..86dcdff9a3 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -64,6 +64,7 @@ target_link_libraries(crashpad_handler_lib if(WIN32) if(MSVC) + target_link_libraries(crashpad_handler_lib PUBLIC crashpad_getopt) target_compile_options(crashpad_handler_lib PRIVATE "/wd4201") endif() endif() diff --git a/third_party/getopt/CMakeLists.txt b/third_party/getopt/CMakeLists.txt index 91dd2ff56e..24175ce593 100644 --- a/third_party/getopt/CMakeLists.txt +++ b/third_party/getopt/CMakeLists.txt @@ -9,6 +9,7 @@ if(MSVC) target_link_libraries(crashpad_getopt PRIVATE $ ) + crashpad_install_target(crashpad_getopt) else() add_library(crashpad_getopt INTERFACE) endif() From e16aa44de092673755f3c225f55997b07a7984c7 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 29 Nov 2021 13:32:48 +0100 Subject: [PATCH 074/478] fix: Pass safeseh flag to MSVC asm compiler (#57) --- util/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 28218b856e..d3d3848d78 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -474,6 +474,9 @@ if(WIN32) target_link_libraries(crashpad_util PRIVATE user32 version winhttp) if(MSVC) target_compile_options(crashpad_util PRIVATE "/wd4201") + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(CMAKE_ASM_MASM_FLAGS "${CMAKE_ASM_MASM_FLAGS} /safeseh") + endif() elseif(MINGW) target_compile_options(crashpad_util PRIVATE $<$:-municode> From a545377d07ff38c06cec05de8026a18955b46c57 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 29 Nov 2021 17:44:53 +0100 Subject: [PATCH 075/478] fix: Use correct ASM files on Windows ARM64 (#58) --- third_party/zlib/CMakeLists.txt | 2 +- util/CMakeLists.txt | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt index f912af5ed6..eeb449ff33 100644 --- a/third_party/zlib/CMakeLists.txt +++ b/third_party/zlib/CMakeLists.txt @@ -35,6 +35,7 @@ else() zlib/trees.c zlib/trees.h zlib/uncompr.c + zlib/x86.h zlib/zconf.h zlib/zlib.h zlib/zutil.c @@ -52,7 +53,6 @@ else() zlib/crc_folding.c zlib/fill_window_sse.c zlib/x86.c - zlib/x86.h ) if(NOT MSVC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index d3d3848d78..eba7b72e8a 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -339,9 +339,17 @@ if(WIN32) win/termination_codes.h win/traits.h win/xp_compat.h - misc/capture_context_win.asm - win/safe_terminate_process.asm ) + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + target_sources(crashpad_util PRIVATE + misc/capture_context_win_arm64.asm + ) + else() + target_sources(crashpad_util PRIVATE + misc/capture_context_win.asm + win/safe_terminate_process.asm + ) + endif() endif() # Copied from: https://github.com/qedsoftware/crashpad/blob/3583c50a6575857abcf140f6ea3b8d11390205b3/util/CMakeLists.txt#L196-L233 From 2ab34ff319a02ae356f2d51e38128306cfca797b Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 3 Dec 2021 15:12:34 +0100 Subject: [PATCH 076/478] Sync CMake files --- client/CMakeLists.txt | 4 ++++ snapshot/CMakeLists.txt | 2 ++ util/CMakeLists.txt | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 5357c8624f..4b35a0f187 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -32,8 +32,12 @@ if(IOS) crashpad_client_ios.cc ios_handler/exception_processor.h ios_handler/exception_processor.mm + ios_handler/in_process_handler.cc + ios_handler/in_process_handler.h ios_handler/in_process_intermediate_dump_handler.cc ios_handler/in_process_intermediate_dump_handler.h + ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc + ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h simulate_crash_ios.h ) endif() diff --git a/snapshot/CMakeLists.txt b/snapshot/CMakeLists.txt index 9d607e401a..f83f4b417d 100644 --- a/snapshot/CMakeLists.txt +++ b/snapshot/CMakeLists.txt @@ -111,6 +111,8 @@ if(LINUX OR ANDROID) target_sources(crashpad_snapshot PRIVATE posix/timezone.cc posix/timezone.h + linux/capture_memory_delegate_linux.cc + linux/capture_memory_delegate_linux.h linux/cpu_context_linux.cc linux/cpu_context_linux.h linux/debug_rendezvous.cc diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index eba7b72e8a..2b42bd9f51 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -167,6 +167,7 @@ if(APPLE) misc/capture_context_mac.S misc/clock_mac.cc misc/paths_mac.cc + net/http_transport_mac.mm synchronization/semaphore_mac.cc ) if(NOT IOS) @@ -195,7 +196,6 @@ if(APPLE) mach/scoped_task_suspend.h mach/task_for_pid.cc mach/task_for_pid.h - net/http_transport_mac.mm posix/process_info_mac.cc process/process_memory_mac.cc process/process_memory_mac.h @@ -205,6 +205,8 @@ if(APPLE) ios/ios_intermediate_dump_data.cc ios/ios_intermediate_dump_data.h ios/ios_intermediate_dump_format.h + ios/ios_intermediate_dump_interface.cc + ios/ios_intermediate_dump_interface.h ios/ios_intermediate_dump_list.cc ios/ios_intermediate_dump_list.h ios/ios_intermediate_dump_map.cc From 96874a17fb5f32680a7ecccd74c70de0596f871d Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 3 Dec 2021 15:15:14 +0100 Subject: [PATCH 077/478] Sync mini_chromium --- third_party/mini_chromium/CMakeLists.txt | 2 +- third_party/mini_chromium/mini_chromium | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 216f3d477f..342b7aa3d9 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -24,9 +24,9 @@ mc_append_sources( files/scoped_file.cc files/scoped_file.h format_macros.h + ignore_result.h logging.cc logging.h - macros.h memory/free_deleter.h memory/page_size.h memory/scoped_policy.h diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 8f7a60f2c6..0e22eed71e 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 8f7a60f2c637f2a3c5d25f320739b3de7c2e325d +Subproject commit 0e22eed71eec97dacbe80822a14c5cd0b580d793 From 6c6bdbece6daa17d10330eae202efbf8400b8193 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 3 Dec 2021 15:36:23 +0100 Subject: [PATCH 078/478] Manually disallow copy construction --- minidump/minidump_stacktrace_writer.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/minidump/minidump_stacktrace_writer.h b/minidump/minidump_stacktrace_writer.h index cddea4e7db..2ba5ae901e 100644 --- a/minidump/minidump_stacktrace_writer.h +++ b/minidump/minidump_stacktrace_writer.h @@ -8,7 +8,6 @@ #include #include -#include "base/macros.h" #include "minidump/minidump_extensions.h" #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_thread_id_map.h" @@ -48,6 +47,11 @@ class MinidumpStacktraceListWriter final : public internal::MinidumpStreamWriter { public: MinidumpStacktraceListWriter(); + + MinidumpStacktraceListWriter(const MinidumpStacktraceListWriter&) = delete; + MinidumpStacktraceListWriter& operator=(const MinidumpStacktraceListWriter&) = + delete; + ~MinidumpStacktraceListWriter() override; //! \brief TODO @@ -77,8 +81,6 @@ class MinidumpStacktraceListWriter final std::vector frames_; std::vector symbol_bytes_; internal::Header stacktrace_header_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpStacktraceListWriter); }; } // namespace crashpad From a32cbe1f9a18bcfccc3952425419059eadd3d95c Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 3 Dec 2021 16:10:05 +0100 Subject: [PATCH 079/478] Simplify Attachment Support diff --- client/crash_report_database_mac.mm | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 8240767d41..d1c0a3ed2e 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -49,7 +49,6 @@ constexpr char kWriteDirectory[] = "new"; constexpr char kUploadPendingDirectory[] = "pending"; constexpr char kCompletedDirectory[] = "completed"; -constexpr char kAttachmentsDirectory[] = "attachments"; constexpr char kSettings[] = "settings.dat"; @@ -72,14 +71,6 @@ constexpr char kXattrDatabaseInitialized[] = "initialized"; -bool AttachmentNameIsOK(const std::string& name) { - for (const char c : name) { - if (c != '_' && c != '-' && c != '.' && !isalnum(c)) - return false; - } - return true; -} - // Ensures that the node at |path| is a directory. If the |path| refers to a // file, rather than a directory, returns false. Otherwise, returns true, // indicating that |path| already was a directory. @@ -471,6 +462,7 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return kFileSystemError; } + upload_report->database_ = this; upload_report->lock_fd.reset(lock.release()); upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); From 2592a777cb34569377d79fce5b3dd883a3001d6c Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 3 Dec 2021 15:23:40 -0800 Subject: [PATCH 080/478] Upgrade LUCI configs to use Mac-11 Bug: chromium:1269911 Change-Id: I6382e6efe3a378916427b824fcfade9c3a72394a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3315414 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- infra/config/generated/cr-buildbucket.cfg | 24 +++++++++++------------ infra/config/generated/project.cfg | 2 +- infra/config/main.star | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index d34621cdf0..bce014ef2b 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -156,7 +156,7 @@ buckets { name: "crashpad_ios_arm64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -193,7 +193,7 @@ buckets { name: "crashpad_ios_arm64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -230,7 +230,7 @@ buckets { name: "crashpad_ios_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -266,7 +266,7 @@ buckets { name: "crashpad_ios_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -368,7 +368,7 @@ buckets { name: "crashpad_mac_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -404,7 +404,7 @@ buckets { name: "crashpad_mac_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -652,7 +652,7 @@ buckets { name: "crashpad_ios_arm64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -686,7 +686,7 @@ buckets { name: "crashpad_ios_arm64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -720,7 +720,7 @@ buckets { name: "crashpad_ios_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -753,7 +753,7 @@ buckets { name: "crashpad_ios_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -846,7 +846,7 @@ buckets { name: "crashpad_mac_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -879,7 +879,7 @@ buckets { name: "crashpad_mac_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-10.15" + dimensions: "os:Mac-11" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" diff --git a/infra/config/generated/project.cfg b/infra/config/generated/project.cfg index 9dcccbfab2..168ec5e99e 100644 --- a/infra/config/generated/project.cfg +++ b/infra/config/generated/project.cfg @@ -7,7 +7,7 @@ name: "crashpad" access: "group:all" lucicfg { - version: "1.30.1" + version: "1.30.4" package_dir: ".." config_dir: "generated" entry_point: "main.star" diff --git a/infra/config/main.star b/infra/config/main.star index f51ef23e1e..d25d175dee 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -159,11 +159,11 @@ def crashpad_dimensions(platform, bucket): if platform == "fuchsia": dimensions["os"] = "Ubuntu-16.04" elif platform == "ios": - dimensions["os"] = "Mac-10.15" + dimensions["os"] = "Mac-11" elif platform == "linux": dimensions["os"] = "Ubuntu-16.04" elif platform == "mac": - dimensions["os"] = "Mac-10.15" + dimensions["os"] = "Mac-11" elif platform == "win": dimensions["os"] = "Windows-10" From cfb5c846745a3f3f28c63a1d74345fc965d2bac9 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 7 Dec 2021 15:37:29 -0800 Subject: [PATCH 081/478] Reland "Reland "Reland "Reland "Reland "Bump Windows SDK to 10.0.19041.0""""" This is a reland of e5e47bc277532ae109a444cbb3646977c93fc077 Previous attempt failed as depot_tools win_sdk helper did not allow the updated path selection for Windows SDKs. This should be fixed by: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/3296663 "[windows_sdk] allow env json to not be relative" > > > > Change-Id: Id0c308a838a8b94ce7d24369ffd168a10730a30a > > > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3256822 > > > > Reviewed-by: Mark Mentovai > > > > Commit-Queue: Mark Mentovai > > > > > > Change-Id: I9e8d14415c12c28b6a230b689d3b791a086d7a06 > > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3260604 > > > Commit-Queue: Alex Gough > > > Reviewed-by: Mark Mentovai > > > > Change-Id: Iafb40bd8799dbfea9308f19e3c6e7568bcba82df > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3260757 > > Commit-Queue: Alex Gough > > Reviewed-by: Mark Mentovai > > Bug: crashpad: > > Change-Id: > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3286783 Change-Id: Idadfe861b64e6c3361e98ca690230f30d113cdab Bug: 1250098 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3321428 Reviewed-by: Mark Mentovai Commit-Queue: Alex Gough --- DEPS | 2 +- infra/config/generated/cr-buildbucket.cfg | 12 ++++++++++++ infra/config/main.star | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/DEPS b/DEPS index c1edb80c15..2ead5cc8d7 100644 --- a/DEPS +++ b/DEPS @@ -106,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chrome_internal/third_party/sdk/windows', - 'version': 'uploaded:2018-06-13' + 'version': 'uploaded:2021-04-28' }, ], 'condition': 'checkout_win and pull_win_toolchain', diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index bce014ef2b..44075a3552 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -450,6 +450,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -483,6 +486,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -922,6 +928,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' @@ -952,6 +961,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' diff --git a/infra/config/main.star b/infra/config/main.star index d25d175dee..2ab43d9f02 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -183,6 +183,11 @@ def crashpad_properties(platform, cpu, config, bucket): if cpu != "x64": properties["target_cpu"] = cpu + if platform == "win": + properties["$depot_tools/windows_sdk"] = { + "version": "uploaded:2021-04-28", + } + if bucket == "ci": properties["$gatekeeper"] = { "group": "client.crashpad", From c1a7d9baea067e436d0c148b8033d7dba7dd757a Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Wed, 8 Dec 2021 01:05:53 +0000 Subject: [PATCH 082/478] Revert "Reland "Reland "Reland "Reland "Reland "Bump Windows SDK to 10.0.19041.0"""""" This reverts commit cfb5c846745a3f3f28c63a1d74345fc965d2bac9. Reason for revert: https://logs.chromium.org/logs/crashpad/buildbucket/cr-buildbucket/8828456030785338865/+/u/generate_build_files_x86/stdout?format=raw Original change's description: > Reland "Reland "Reland "Reland "Reland "Bump Windows SDK to 10.0.19041.0""""" > > This is a reland of e5e47bc277532ae109a444cbb3646977c93fc077 > > Previous attempt failed as depot_tools win_sdk helper did not allow > the updated path selection for Windows SDKs. This should be fixed by: > https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/3296663 > "[windows_sdk] allow env json to not be relative" > > > > > > Change-Id: Id0c308a838a8b94ce7d24369ffd168a10730a30a > > > > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3256822 > > > > > Reviewed-by: Mark Mentovai > > > > > Commit-Queue: Mark Mentovai > > > > > > > > Change-Id: I9e8d14415c12c28b6a230b689d3b791a086d7a06 > > > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3260604 > > > > Commit-Queue: Alex Gough > > > > Reviewed-by: Mark Mentovai > > > > > > Change-Id: Iafb40bd8799dbfea9308f19e3c6e7568bcba82df > > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3260757 > > > Commit-Queue: Alex Gough > > > Reviewed-by: Mark Mentovai > > > Bug: crashpad: > > > > Change-Id: > > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3286783 > > Change-Id: Idadfe861b64e6c3361e98ca690230f30d113cdab > Bug: 1250098 > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3321428 > Reviewed-by: Mark Mentovai > Commit-Queue: Alex Gough Bug: 1250098 Change-Id: I346ee73d690f3102b28df10d4cd2a9a7273608fd No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3321436 Bot-Commit: Rubber Stamper Commit-Queue: Alex Gough --- DEPS | 2 +- infra/config/generated/cr-buildbucket.cfg | 12 ------------ infra/config/main.star | 5 ----- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/DEPS b/DEPS index 2ead5cc8d7..c1edb80c15 100644 --- a/DEPS +++ b/DEPS @@ -106,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chrome_internal/third_party/sdk/windows', - 'version': 'uploaded:2021-04-28' + 'version': 'uploaded:2018-06-13' }, ], 'condition': 'checkout_win and pull_win_toolchain', diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 44075a3552..bce014ef2b 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -450,9 +450,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -486,9 +483,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -928,9 +922,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' @@ -961,9 +952,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' diff --git a/infra/config/main.star b/infra/config/main.star index 2ab43d9f02..d25d175dee 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -183,11 +183,6 @@ def crashpad_properties(platform, cpu, config, bucket): if cpu != "x64": properties["target_cpu"] = cpu - if platform == "win": - properties["$depot_tools/windows_sdk"] = { - "version": "uploaded:2021-04-28", - } - if bucket == "ci": properties["$gatekeeper"] = { "group": "client.crashpad", From a253f320d58a04c3e47f1e99a5d303a93f545317 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Mon, 13 Dec 2021 13:48:45 -0800 Subject: [PATCH 083/478] linux, win: allow disabling extra memory collection Change-Id: If95c89d554c061522627681af78c8c0d1725df2c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3335359 Reviewed-by: Mark Mentovai --- client/crashpad_client_linux_test.cc | 23 ++++++--- snapshot/crashpad_info_client_options_test.cc | 2 +- .../linux/capture_memory_delegate_linux.cc | 2 +- snapshot/linux/exception_snapshot_linux.cc | 15 ++++-- snapshot/linux/exception_snapshot_linux.h | 3 +- .../linux/exception_snapshot_linux_test.cc | 9 ++-- snapshot/linux/process_snapshot_linux.cc | 21 +++++--- snapshot/win/capture_memory_delegate_win.cc | 2 +- snapshot/win/exception_snapshot_win.cc | 8 ++- snapshot/win/exception_snapshot_win.h | 3 +- snapshot/win/process_snapshot_win.cc | 51 +++++++++---------- snapshot/win/process_snapshot_win.h | 3 +- 12 files changed, 84 insertions(+), 58 deletions(-) diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index a3ddc31c8a..ddf15390a7 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -26,6 +26,7 @@ #include "client/annotation.h" #include "client/annotation_list.h" #include "client/crash_report_database.h" +#include "client/crashpad_info.h" #include "client/simulate_crash.h" #include "gtest/gtest.h" #include "snapshot/annotation_snapshot.h" @@ -73,12 +74,13 @@ struct StartHandlerForSelfTestOptions { bool set_first_chance_handler; bool crash_non_main_thread; bool client_uses_signals; + bool gather_indirectly_referenced_memory; CrashType crash_type; }; class StartHandlerForSelfTest : public testing::TestWithParam< - std::tuple> { + std::tuple> { public: StartHandlerForSelfTest() = default; @@ -92,6 +94,7 @@ class StartHandlerForSelfTest options_.set_first_chance_handler, options_.crash_non_main_thread, options_.client_uses_signals, + options_.gather_indirectly_referenced_memory, options_.crash_type) = GetParam(); } @@ -147,7 +150,8 @@ void ValidateAttachment(const CrashReportDatabase::UploadReport* report) { 0); } -void ValidateExtraMemory(const ProcessSnapshotMinidump& minidump) { +void ValidateExtraMemory(const StartHandlerForSelfTestOptions& options, + const ProcessSnapshotMinidump& minidump) { // Verify that if we have an exception, then the code around the instruction // pointer is included in the extra memory. const ExceptionSnapshot* exception = minidump.Exception(); @@ -164,10 +168,11 @@ void ValidateExtraMemory(const ProcessSnapshotMinidump& minidump) { break; } } - EXPECT_TRUE(pc_found); + EXPECT_EQ(pc_found, options.gather_indirectly_referenced_memory); } -void ValidateDump(const CrashReportDatabase::UploadReport* report) { +void ValidateDump(const StartHandlerForSelfTestOptions& options, + const CrashReportDatabase::UploadReport* report) { ProcessSnapshotMinidump minidump_snapshot; ASSERT_TRUE(minidump_snapshot.Initialize(report->Reader())); @@ -184,7 +189,7 @@ void ValidateDump(const CrashReportDatabase::UploadReport* report) { #endif ValidateAttachment(report); - ValidateExtraMemory(minidump_snapshot); + ValidateExtraMemory(options, minidump_snapshot); for (const ModuleSnapshot* module : minidump_snapshot.Modules()) { for (const AnnotationSnapshot& annotation : module->AnnotationObjects()) { @@ -330,6 +335,11 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) { client_handler, SA_ONSTACK, &old_actions)); } + if (options.gather_indirectly_referenced_memory) { + CrashpadInfo::GetCrashpadInfo()->set_gather_indirectly_referenced_memory( + TriState::kEnabled, 1024 * 1024 * 4); + } + base::FilePath handler_path = TestPaths::Executable().DirName().Append( FILE_PATH_LITERAL("crashpad_handler")); @@ -442,7 +452,7 @@ class StartHandlerForSelfInChildTest : public MultiprocessExec { std::unique_ptr report; ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report), CrashReportDatabase::kNoError); - ValidateDump(report.get()); + ValidateDump(options_, report.get()); } StartHandlerForSelfTestOptions options_; @@ -471,6 +481,7 @@ INSTANTIATE_TEST_SUITE_P( testing::Bool(), testing::Bool(), testing::Bool(), + testing::Bool(), testing::Values(CrashType::kSimulated, CrashType::kBuiltinTrap, CrashType::kInfiniteRecursion))); diff --git a/snapshot/crashpad_info_client_options_test.cc b/snapshot/crashpad_info_client_options_test.cc index f5baa5bc68..4476e216ca 100644 --- a/snapshot/crashpad_info_client_options_test.cc +++ b/snapshot/crashpad_info_client_options_test.cc @@ -144,7 +144,7 @@ TEST(CrashpadInfoClientOptions, OneModule) { EXPECT_EQ(options.crashpad_handler_behavior, TriState::kUnset); EXPECT_EQ(options.system_crash_reporter_forwarding, TriState::kUnset); EXPECT_EQ(options.gather_indirectly_referenced_memory, TriState::kEnabled); - EXPECT_EQ(options.indirectly_referenced_memory_cap, 1234u); + EXPECT_LE(options.indirectly_referenced_memory_cap, 1234u); } } diff --git a/snapshot/linux/capture_memory_delegate_linux.cc b/snapshot/linux/capture_memory_delegate_linux.cc index 4f1587400c..bf4c7b8e0d 100644 --- a/snapshot/linux/capture_memory_delegate_linux.cc +++ b/snapshot/linux/capture_memory_delegate_linux.cc @@ -57,7 +57,7 @@ void CaptureMemoryDelegateLinux::AddNewMemorySnapshot( return; if (range.size() == 0) return; - if (budget_remaining_ && *budget_remaining_ == 0) + if (!budget_remaining_ || *budget_remaining_ == 0) return; snapshots_->push_back(std::make_unique()); internal::MemorySnapshotGeneric* snapshot = snapshots_->back().get(); diff --git a/snapshot/linux/exception_snapshot_linux.cc b/snapshot/linux/exception_snapshot_linux.cc index 42d0eb0b29..6726d04814 100644 --- a/snapshot/linux/exception_snapshot_linux.cc +++ b/snapshot/linux/exception_snapshot_linux.cc @@ -326,10 +326,12 @@ bool ExceptionSnapshotLinux::ReadContext( #endif // ARCH_CPU_X86_FAMILY -bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, - LinuxVMAddress siginfo_address, - LinuxVMAddress context_address, - pid_t thread_id) { +bool ExceptionSnapshotLinux::Initialize( + ProcessReaderLinux* process_reader, + LinuxVMAddress siginfo_address, + LinuxVMAddress context_address, + pid_t thread_id, + uint32_t* gather_indirectly_referenced_memory_cap) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); thread_id_ = thread_id; @@ -359,7 +361,10 @@ bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, } CaptureMemoryDelegateLinux capture_memory_delegate( - process_reader, thread, &extra_memory_, nullptr); + process_reader, + thread, + &extra_memory_, + gather_indirectly_referenced_memory_cap); CaptureMemory::PointedToByContext(context_, &capture_memory_delegate); INITIALIZATION_STATE_SET_VALID(initialized_); diff --git a/snapshot/linux/exception_snapshot_linux.h b/snapshot/linux/exception_snapshot_linux.h index 1719f0be76..05f6004e11 100644 --- a/snapshot/linux/exception_snapshot_linux.h +++ b/snapshot/linux/exception_snapshot_linux.h @@ -59,7 +59,8 @@ class ExceptionSnapshotLinux final : public ExceptionSnapshot { bool Initialize(ProcessReaderLinux* process_reader, LinuxVMAddress siginfo_address, LinuxVMAddress context_address, - pid_t thread_id); + pid_t thread_id, + uint32_t* gather_indirectly_referenced_memory_cap); // ExceptionSnapshot: diff --git a/snapshot/linux/exception_snapshot_linux_test.cc b/snapshot/linux/exception_snapshot_linux_test.cc index 51d3fd3808..91be497a77 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -320,7 +320,8 @@ TEST(ExceptionSnapshotLinux, SelfBasic) { ASSERT_TRUE(exception.Initialize(&process_reader, FromPointerCast(&siginfo), FromPointerCast(&context), - gettid())); + gettid(), + nullptr)); EXPECT_EQ(exception.Exception(), static_cast(siginfo.si_signo)); EXPECT_EQ(exception.ExceptionInfo(), static_cast(siginfo.si_code)); EXPECT_EQ(exception.ExceptionAddress(), @@ -393,7 +394,8 @@ class RaiseTest { ASSERT_TRUE(exception.Initialize(&process_reader, FromPointerCast(siginfo), FromPointerCast(context), - gettid())); + gettid(), + nullptr)); EXPECT_EQ(exception.Exception(), static_cast(kSigno)); @@ -464,7 +466,8 @@ class TimerTest { ASSERT_TRUE(exception.Initialize(&process_reader, FromPointerCast(siginfo), FromPointerCast(context), - gettid())); + gettid(), + nullptr)); EXPECT_EQ(exception.Exception(), static_cast(kSigno)); diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 6233134795..a730b29eb5 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -42,10 +42,9 @@ bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection) { client_id_.InitializeToZero(); system_.Initialize(&process_reader_, &snapshot_time_); + InitializeModules(); GetCrashpadOptionsInternal((&options_)); - InitializeThreads(); - InitializeModules(); InitializeAnnotations(); INITIALIZATION_STATE_SET_VALID(initialized_); @@ -83,11 +82,17 @@ bool ProcessSnapshotLinux::InitializeException( info.thread_id = exception_thread_id; } + uint32_t* budget_remaining_pointer = + options_.gather_indirectly_referenced_memory == TriState::kEnabled + ? &options_.indirectly_referenced_memory_cap + : nullptr; + exception_.reset(new internal::ExceptionSnapshotLinux()); if (!exception_->Initialize(&process_reader_, info.siginfo_address, info.context_address, - info.thread_id)) { + info.thread_id, + budget_remaining_pointer)) { exception_.reset(); return false; } @@ -269,11 +274,11 @@ const ProcessMemory* ProcessSnapshotLinux::Memory() const { void ProcessSnapshotLinux::InitializeThreads() { const std::vector& process_reader_threads = process_reader_.Threads(); - uint32_t* budget_remaining_pointer = nullptr; - uint32_t budget_remaining = options_.indirectly_referenced_memory_cap; - if (options_.gather_indirectly_referenced_memory == TriState::kEnabled) { - budget_remaining_pointer = &budget_remaining; - } + uint32_t* budget_remaining_pointer = + options_.gather_indirectly_referenced_memory == TriState::kEnabled + ? &options_.indirectly_referenced_memory_cap + : nullptr; + for (const ProcessReaderLinux::Thread& process_reader_thread : process_reader_threads) { auto thread = std::make_unique(); diff --git a/snapshot/win/capture_memory_delegate_win.cc b/snapshot/win/capture_memory_delegate_win.cc index ee5e5d644b..3d3cdd546f 100644 --- a/snapshot/win/capture_memory_delegate_win.cc +++ b/snapshot/win/capture_memory_delegate_win.cc @@ -55,7 +55,7 @@ void CaptureMemoryDelegateWin::AddNewMemorySnapshot( return; if (range.size() == 0) return; - if (budget_remaining_ && *budget_remaining_ == 0) + if (!budget_remaining_ || *budget_remaining_ == 0) return; snapshots_->push_back(std::make_unique()); internal::MemorySnapshotGeneric* snapshot = snapshots_->back().get(); diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index 5759652d45..5b306cd5bf 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -84,7 +84,8 @@ ExceptionSnapshotWin::~ExceptionSnapshotWin() { bool ExceptionSnapshotWin::Initialize( ProcessReaderWin* process_reader, DWORD thread_id, - WinVMAddress exception_pointers_address) { + WinVMAddress exception_pointers_address, + uint32_t* gather_indirectly_referenced_memory_cap) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); const ProcessReaderWin::Thread* thread = nullptr; @@ -132,7 +133,10 @@ bool ExceptionSnapshotWin::Initialize( #endif CaptureMemoryDelegateWin capture_memory_delegate( - process_reader, *thread, &extra_memory_, nullptr); + process_reader, + *thread, + &extra_memory_, + gather_indirectly_referenced_memory_cap); CaptureMemory::PointedToByContext(context_, &capture_memory_delegate); INITIALIZATION_STATE_SET_VALID(initialized_); diff --git a/snapshot/win/exception_snapshot_win.h b/snapshot/win/exception_snapshot_win.h index 9167a9ef63..b8fa73530a 100644 --- a/snapshot/win/exception_snapshot_win.h +++ b/snapshot/win/exception_snapshot_win.h @@ -72,7 +72,8 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot { //! an appropriate message logged. bool Initialize(ProcessReaderWin* process_reader, DWORD thread_id, - WinVMAddress exception_pointers); + WinVMAddress exception_pointers, + uint32_t* gather_indirectly_referenced_memory_cap); // ExceptionSnapshot: diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index b60ea38ea1..fee843c76d 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -63,6 +63,26 @@ bool ProcessSnapshotWin::Initialize( if (!process_reader_.Initialize(process, suspension_state)) return false; + client_id_.InitializeToZero(); + system_.Initialize(&process_reader_); + + if (process_reader_.Is64Bit()) { + InitializePebData( + debug_critical_section_address); + } else { + InitializePebData( + debug_critical_section_address); + } + + InitializeModules(); + InitializeUnloadedModules(); + + GetCrashpadOptionsInternal(&options_); + uint32_t* budget_remaining_pointer = + options_.gather_indirectly_referenced_memory == TriState::kEnabled + ? &options_.indirectly_referenced_memory_cap + : nullptr; + if (exception_information_address != 0) { ExceptionInformation exception_information = {}; if (!process_reader_.Memory()->Read(exception_information_address, @@ -75,31 +95,14 @@ bool ProcessSnapshotWin::Initialize( exception_.reset(new internal::ExceptionSnapshotWin()); if (!exception_->Initialize(&process_reader_, exception_information.thread_id, - exception_information.exception_pointers)) { + exception_information.exception_pointers, + budget_remaining_pointer)) { exception_.reset(); return false; } } - client_id_.InitializeToZero(); - system_.Initialize(&process_reader_); - - if (process_reader_.Is64Bit()) { - InitializePebData( - debug_critical_section_address); - } else { - InitializePebData( - debug_critical_section_address); - } - - InitializeModules(); - InitializeUnloadedModules(); - - GetCrashpadOptionsInternal(&options_); - - InitializeThreads( - options_.gather_indirectly_referenced_memory == TriState::kEnabled, - options_.indirectly_referenced_memory_cap); + InitializeThreads(budget_remaining_pointer); for (const MEMORY_BASIC_INFORMATION64& mbi : process_reader_.GetProcessInfo().MemoryInfo()) { @@ -239,15 +242,9 @@ const ProcessMemory* ProcessSnapshotWin::Memory() const { return process_reader_.Memory(); } -void ProcessSnapshotWin::InitializeThreads( - bool gather_indirectly_referenced_memory, - uint32_t indirectly_referenced_memory_cap) { +void ProcessSnapshotWin::InitializeThreads(uint32_t* budget_remaining_pointer) { const std::vector& process_reader_threads = process_reader_.Threads(); - uint32_t* budget_remaining_pointer = nullptr; - uint32_t budget_remaining = indirectly_referenced_memory_cap; - if (gather_indirectly_referenced_memory) - budget_remaining_pointer = &budget_remaining; for (const ProcessReaderWin::Thread& process_reader_thread : process_reader_threads) { auto thread = std::make_unique(); diff --git a/snapshot/win/process_snapshot_win.h b/snapshot/win/process_snapshot_win.h index 7a8ae2fd3f..002107078b 100644 --- a/snapshot/win/process_snapshot_win.h +++ b/snapshot/win/process_snapshot_win.h @@ -137,8 +137,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot { private: // Initializes threads_ on behalf of Initialize(). - void InitializeThreads(bool gather_indirectly_referenced_memory, - uint32_t indirectly_referenced_memory_cap); + void InitializeThreads(uint32_t* indirectly_referenced_memory_cap); // Initializes modules_ on behalf of Initialize(). void InitializeModules(); From 05e4aedfb382b449b087cd505ebb340f291a4300 Mon Sep 17 00:00:00 2001 From: Joshua Seaton Date: Mon, 13 Dec 2021 14:07:27 -0800 Subject: [PATCH 084/478] [googletest] Roll pin googletest is rolled to 5bcd8e3bb929714e031a542d303f818e5a5af45d to pick up changes that affect how process information is read on fuchsia. The existing pin is from April 26 2021 and the new one is from June 8: this is a conservative roll - and the new pin matches that of other fuchsia SDK partners. Bug: fuchsia:30751 Change-Id: Ie1c4d075cfc2968c0984671c3afd0bc50fe00d3f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3335589 Reviewed-by: Francois Rousseau Reviewed-by: Mark Mentovai Commit-Queue: Francois Rousseau --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index c1edb80c15..19a773fac1 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { }, 'crashpad/third_party/googletest/googletest': Var('chromium_git') + '/external/github.com/google/googletest@' + - '11da093e0477185dbd78abaaa9f99db15be498d0', + '5bcd8e3bb929714e031a542d303f818e5a5af45d', 'crashpad/third_party/lss/lss': Var('chromium_git') + '/linux-syscall-support.git@' + '7bde79cc274d06451bf65ae82c012a5d3e476b5a', From 398908903e0c85e3da26f9e3349f4b093fcaa401 Mon Sep 17 00:00:00 2001 From: Adrian Danis Date: Mon, 13 Dec 2021 13:29:45 +1100 Subject: [PATCH 085/478] Fuchsia: Migrate to zx_system_get_page_size Bug: fuchsia:67899 Change-Id: Id6fb9f67316dd60c939d9b8b6c6d9330831a04a2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3331859 Reviewed-by: Francois Rousseau Commit-Queue: Francois Rousseau --- snapshot/fuchsia/process_snapshot_fuchsia_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc index 496d97a82d..9389868ba0 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -56,7 +56,7 @@ CRASHPAD_CHILD_TEST_MAIN(AddressSpaceChildTestMain) { // correctly. for (const auto& t : kTestMappingPermAndSizes) { zx_handle_t vmo = ZX_HANDLE_INVALID; - const size_t size = t.pages * PAGE_SIZE; + const size_t size = t.pages * zx_system_get_page_size(); zx_status_t status = zx_vmo_create(size, 0, &vmo); ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create"; status = zx_vmo_replace_as_executable(vmo, ZX_HANDLE_INVALID, &vmo); @@ -126,7 +126,7 @@ class AddressSpaceTest : public MultiprocessExec { const auto& t = kTestMappingPermAndSizes[i]; EXPECT_TRUE(HasSingleMatchingMapping(process_snapshot.MemoryMap(), test_addresses[i], - t.pages * PAGE_SIZE, + t.pages * zx_system_get_page_size(), t.minidump_perm)) << base::StringPrintf( "index %zu, zircon_perm 0x%x, minidump_perm 0x%x", From a8683138db568ad89052587d081d280682439bc4 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 14 Dec 2021 03:56:05 -0800 Subject: [PATCH 086/478] Reland x6 "Bump Windows SDK to 10.0.19041.0" Reland of cfb5c846745a3f3f28c63a1d74345fc965d2bac9. CL configures crashpad builders to use cipd packaged Windows SDK version 10.0.19041 and updates mini_chromium to account for new SDK layout[0]. [0] https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/3328284 Bug: 1250098 Change-Id: Ie8ea11497e31d51478041829c872b47f5c982ab8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3334271 Reviewed-by: Mark Mentovai Commit-Queue: Alex Gough --- DEPS | 4 ++-- infra/config/generated/cr-buildbucket.cfg | 12 ++++++++++++ infra/config/main.star | 5 +++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 19a773fac1..8d5d58be18 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '0e22eed71eec97dacbe80822a14c5cd0b580d793', + '4c50bd67f8db485f9cdd887b4bf7f498eaf49c17', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', @@ -106,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chrome_internal/third_party/sdk/windows', - 'version': 'uploaded:2018-06-13' + 'version': 'uploaded:2021-04-28' }, ], 'condition': 'checkout_win and pull_win_toolchain', diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index bce014ef2b..44075a3552 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -450,6 +450,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -483,6 +486,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -922,6 +928,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' @@ -952,6 +961,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' diff --git a/infra/config/main.star b/infra/config/main.star index d25d175dee..2ab43d9f02 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -183,6 +183,11 @@ def crashpad_properties(platform, cpu, config, bucket): if cpu != "x64": properties["target_cpu"] = cpu + if platform == "win": + properties["$depot_tools/windows_sdk"] = { + "version": "uploaded:2021-04-28", + } + if bucket == "ci": properties["$gatekeeper"] = { "group": "client.crashpad", From 3e234dfe967cab4b34f08a0ceb946eb097a088ab Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 14 Dec 2021 13:24:33 +0000 Subject: [PATCH 087/478] Revert "Reland x6 "Bump Windows SDK to 10.0.19041.0"" This reverts commit a8683138db568ad89052587d081d280682439bc4. Reason for revert: https://logs.chromium.org/logs/crashpad/buildbucket/cr-buildbucket/8827866127654006481/+/u/generate_build_files_x86/stdout?format=raw Original change's description: > Reland x6 "Bump Windows SDK to 10.0.19041.0" > > Reland of cfb5c846745a3f3f28c63a1d74345fc965d2bac9. > > CL configures crashpad builders to use cipd packaged Windows SDK > version 10.0.19041 and updates mini_chromium to account for new > SDK layout[0]. > > [0] https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/3328284 > > Bug: 1250098 > Change-Id: Ie8ea11497e31d51478041829c872b47f5c982ab8 > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3334271 > Reviewed-by: Mark Mentovai > Commit-Queue: Alex Gough Bug: 1250098 Change-Id: Icef5e7a8c475c06274c935481df22fae1c6cdc3a No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3338854 Bot-Commit: Rubber Stamper Commit-Queue: Alex Gough --- DEPS | 4 ++-- infra/config/generated/cr-buildbucket.cfg | 12 ------------ infra/config/main.star | 5 ----- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/DEPS b/DEPS index 8d5d58be18..19a773fac1 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '4c50bd67f8db485f9cdd887b4bf7f498eaf49c17', + '0e22eed71eec97dacbe80822a14c5cd0b580d793', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', @@ -106,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chrome_internal/third_party/sdk/windows', - 'version': 'uploaded:2021-04-28' + 'version': 'uploaded:2018-06-13' }, ], 'condition': 'checkout_win and pull_win_toolchain', diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 44075a3552..bce014ef2b 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -450,9 +450,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -486,9 +483,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -928,9 +922,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' @@ -961,9 +952,6 @@ buckets { } properties: '{' - ' "$depot_tools/windows_sdk": {' - ' "version": "uploaded:2021-04-28"' - ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' diff --git a/infra/config/main.star b/infra/config/main.star index 2ab43d9f02..d25d175dee 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -183,11 +183,6 @@ def crashpad_properties(platform, cpu, config, bucket): if cpu != "x64": properties["target_cpu"] = cpu - if platform == "win": - properties["$depot_tools/windows_sdk"] = { - "version": "uploaded:2021-04-28", - } - if bucket == "ci": properties["$gatekeeper"] = { "group": "client.crashpad", From ff50a9e8c443bc053b7426cfe58bf25ccdad786b Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 14 Dec 2021 09:22:22 -0800 Subject: [PATCH 088/478] Reland x7 "Bump Windows SDK to 10.0.19041.0" This is a reland of a8683138db568ad89052587d081d280682439bc4 x86 env var VSINSTALLDIR=path\.\ was interpolated into a gn vars file with a trailing slash. mini_chromium has been updated to account for this[0]. [0] https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/3338622 Original change's description: > Reland x6 "Bump Windows SDK to 10.0.19041.0" > > Reland of cfb5c846745a3f3f28c63a1d74345fc965d2bac9. > > CL configures crashpad builders to use cipd packaged Windows SDK > version 10.0.19041 and updates mini_chromium to account for new > SDK layout[0]. > > [0] https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/3328284 > > Bug: 1250098 > Change-Id: Ie8ea11497e31d51478041829c872b47f5c982ab8 > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3334271 > Reviewed-by: Mark Mentovai > Commit-Queue: Alex Gough Bug: 1250098 Change-Id: Ie8145d498f4f3f10fd6195d8e0ad5a82bf25933b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3339382 Reviewed-by: Mark Mentovai Commit-Queue: Alex Gough --- DEPS | 4 ++-- infra/config/generated/cr-buildbucket.cfg | 12 ++++++++++++ infra/config/main.star | 5 +++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 19a773fac1..e13bea8945 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '0e22eed71eec97dacbe80822a14c5cd0b580d793', + '502930381b23c5fa3911c8b82ec3e4ba6ceb3658', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', @@ -106,7 +106,7 @@ deps = { 'packages': [ { 'package': 'chrome_internal/third_party/sdk/windows', - 'version': 'uploaded:2018-06-13' + 'version': 'uploaded:2021-04-28' }, ], 'condition': 'checkout_win and pull_win_toolchain', diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index bce014ef2b..44075a3552 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -450,6 +450,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -483,6 +486,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$gatekeeper": {' ' "group": "client.crashpad"' ' },' @@ -922,6 +928,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' @@ -952,6 +961,9 @@ buckets { } properties: '{' + ' "$depot_tools/windows_sdk": {' + ' "version": "uploaded:2021-04-28"' + ' },' ' "$kitchen": {' ' "devshell": true,' ' "git_auth": true' diff --git a/infra/config/main.star b/infra/config/main.star index d25d175dee..2ab43d9f02 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -183,6 +183,11 @@ def crashpad_properties(platform, cpu, config, bucket): if cpu != "x64": properties["target_cpu"] = cpu + if platform == "win": + properties["$depot_tools/windows_sdk"] = { + "version": "uploaded:2021-04-28", + } + if bucket == "ci": properties["$gatekeeper"] = { "group": "client.crashpad", From b03c11533c1487cc7daf3f74daf6d797288d4c22 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 15 Dec 2021 10:59:57 -0800 Subject: [PATCH 089/478] Remove unnecessary lines in CaptureMemoryDelegate Change-Id: I172c5bf9f399791a9bfecd26553450a2ed30315b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3342502 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- snapshot/linux/capture_memory_delegate_linux.cc | 14 ++++++-------- snapshot/win/capture_memory_delegate_win.cc | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/snapshot/linux/capture_memory_delegate_linux.cc b/snapshot/linux/capture_memory_delegate_linux.cc index bf4c7b8e0d..918e572d59 100644 --- a/snapshot/linux/capture_memory_delegate_linux.cc +++ b/snapshot/linux/capture_memory_delegate_linux.cc @@ -62,14 +62,12 @@ void CaptureMemoryDelegateLinux::AddNewMemorySnapshot( snapshots_->push_back(std::make_unique()); internal::MemorySnapshotGeneric* snapshot = snapshots_->back().get(); snapshot->Initialize(process_reader_->Memory(), range.base(), range.size()); - if (budget_remaining_) { - if (!base::IsValueInRangeForNumericType(range.size())) { - *budget_remaining_ = 0; - } else { - int64_t temp = *budget_remaining_; - temp -= range.size(); - *budget_remaining_ = base::saturated_cast(temp); - } + if (!base::IsValueInRangeForNumericType(range.size())) { + *budget_remaining_ = 0; + } else { + int64_t temp = *budget_remaining_; + temp -= range.size(); + *budget_remaining_ = base::saturated_cast(temp); } } diff --git a/snapshot/win/capture_memory_delegate_win.cc b/snapshot/win/capture_memory_delegate_win.cc index 3d3cdd546f..43067caa6d 100644 --- a/snapshot/win/capture_memory_delegate_win.cc +++ b/snapshot/win/capture_memory_delegate_win.cc @@ -60,14 +60,12 @@ void CaptureMemoryDelegateWin::AddNewMemorySnapshot( snapshots_->push_back(std::make_unique()); internal::MemorySnapshotGeneric* snapshot = snapshots_->back().get(); snapshot->Initialize(process_reader_->Memory(), range.base(), range.size()); - if (budget_remaining_) { - if (!base::IsValueInRangeForNumericType(range.size())) { - *budget_remaining_ = 0; - } else { - int64_t temp = *budget_remaining_; - temp -= range.size(); - *budget_remaining_ = base::saturated_cast(temp); - } + if (!base::IsValueInRangeForNumericType(range.size())) { + *budget_remaining_ = 0; + } else { + int64_t temp = *budget_remaining_; + temp -= range.size(); + *budget_remaining_ = base::saturated_cast(temp); } } From 5cc0d543d0e5dadba03a6bf7dd8161fb78ab07b5 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 15 Dec 2021 11:01:28 -0800 Subject: [PATCH 090/478] Remove obsolete LUCI experiment Change-Id: I755d8d6b9490c82ca3044118501add36a532053d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3336402 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- infra/config/main.star | 4 ---- 1 file changed, 4 deletions(-) diff --git a/infra/config/main.star b/infra/config/main.star index 2ab43d9f02..1069520f49 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -15,10 +15,6 @@ lucicfg.check_version("1.28.0", "Please update depot_tools") -# Enable LUCI Realms support and Launch 100% of Swarming tasks for builds in -# "realms-aware mode". -lucicfg.enable_experiment("crbug.com/1085650") - REPO_URL = "https://chromium.googlesource.com/crashpad/crashpad" REVIEW_URL = "https://chromium-review.googlesource.com/crashpad/crashpad" From 0ea32e0c7bc2569e597e412a20151ad8a7e64623 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Mon, 20 Dec 2021 12:57:44 -0800 Subject: [PATCH 091/478] linux: initialize padding bytes in tests for msan Bug: chromium:1281317 Change-Id: I83a50b851e9648e5270793c9149206103ac40ed1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3350751 Reviewed-by: Justin Cohen Commit-Queue: Joshua Peraza --- client/crashpad_client_linux_test.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index ddf15390a7..1ab974e7f7 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -90,6 +90,9 @@ class StartHandlerForSelfTest ~StartHandlerForSelfTest() = default; void SetUp() override { + // MSAN requires that padding bytes have been initialized for structs that + // are written to files. + memset(&options_, 0, sizeof(options_)); std::tie(options_.start_handler_at_crash, options_.set_first_chance_handler, options_.crash_non_main_thread, From 821d265ea9fa52b15908481b1e684b2d68d50ac6 Mon Sep 17 00:00:00 2001 From: Nathan Mulcahey Date: Wed, 5 Jan 2022 13:39:23 -0800 Subject: [PATCH 092/478] [lss] Roll lss and update Fuchsia location Fuchsia is currently pulling in lss twice, this rolls crashpad up to HEAD and redirects the Fuchsia build to use the existing copy in our dependencies. Change-Id: Ib698ee72d3d1881d22128bc94a1f6f17185a0755 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3364805 Reviewed-by: Francois Rousseau Commit-Queue: Francois Rousseau --- DEPS | 2 +- third_party/lss/lss.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e13bea8945..bcd6238ab9 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ deps = { '5bcd8e3bb929714e031a542d303f818e5a5af45d', 'crashpad/third_party/lss/lss': Var('chromium_git') + '/linux-syscall-support.git@' + - '7bde79cc274d06451bf65ae82c012a5d3e476b5a', + 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + '502930381b23c5fa3911c8b82ec3e4ba6ceb3658', diff --git a/third_party/lss/lss.h b/third_party/lss/lss.h index 2646b6c008..0bdd381c63 100644 --- a/third_party/lss/lss.h +++ b/third_party/lss/lss.h @@ -20,7 +20,7 @@ #elif defined(CRASHPAD_LSS_SOURCE_EMBEDDED) #include "third_party/lss/lss/linux_syscall_support.h" #elif defined(CRASHPAD_LSS_SOURCE_FUCHSIA) -#include "../../../../third_party/lss/linux_syscall_support.h" +#include "../../../../third_party/linux-syscall-support/linux_syscall_support.h" #else #error Unknown lss source #endif From ae39cec086fc5a35b67e5b6e1797dcfbd5374d70 Mon Sep 17 00:00:00 2001 From: Nathan Mulcahey Date: Thu, 6 Jan 2022 11:43:10 -0800 Subject: [PATCH 093/478] [util/net] Fix append to undefined `defines` From the Fuchsia build: ``` ERROR at //third_party/crashpad/util/BUILD.gn:658:7: Undefined identifier. defines += [ "CRASHPAD_USE_BORINGSSL" ] ^------ See //src/developer/forensics/crash_reports/BUILD.gn:127:5: which caused the file to be included. "//third_party/crashpad/util", ^---------------------------- ``` Change-Id: I1f563e5bb599b3a7a83ee8211037ee1d7464bd62 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3370891 Reviewed-by: Francois Rousseau Commit-Queue: Francois Rousseau Reviewed-by: Robert Sesek --- util/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 7b70440887..586b79ca7b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -655,7 +655,7 @@ crashpad_static_library("net") { if (crashpad_http_transport_impl == "socket") { sources += [ "net/http_transport_socket.cc" ] if (crashpad_use_boringssl_for_http_transport_socket) { - defines += [ "CRASHPAD_USE_BORINGSSL" ] + defines = [ "CRASHPAD_USE_BORINGSSL" ] if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { deps += [ "//third_party/boringssl" ] From 4a539c714d13d43595a785eb6bbb76d9cd486944 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Thu, 6 Jan 2022 20:15:49 -0500 Subject: [PATCH 094/478] Update mini_chromium to 6562d2d0b2a86026a0c8bfc89d95c0a547ed9e5e 6562d2d0b2a8 Compile as C++17 by using -std=c++17 (and /std:c++17 on Windows) Change-Id: I10c209e8147425af77392e7649210ab68a5d27a7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3371781 Reviewed-by: Joshua Peraza Commit-Queue: Mark Mentovai --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index bcd6238ab9..2652447518 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '502930381b23c5fa3911c8b82ec3e4ba6ceb3658', + '6562d2d0b2a86026a0c8bfc89d95c0a547ed9e5e', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 7aec28511053720196b2d9668ba407887a806aae Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 7 Jan 2022 13:44:02 -0500 Subject: [PATCH 095/478] Update mini_chromium to 0243b40af70e34c81fc8a30d9b15cd276b2d49ba 0243b40af70e win: Actually compile C++ as C++17, and fix __cplusplus macro Change-Id: If430b97d1cf846746a5226638e04b3a2cdb5efce Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3372325 Reviewed-by: Joshua Peraza Commit-Queue: Mark Mentovai --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2652447518..7bdeef7361 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '6562d2d0b2a86026a0c8bfc89d95c0a547ed9e5e', + '0243b40af70e34c81fc8a30d9b15cd276b2d49ba', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From ee230eef028e61ec6da72e40211579727dc4c1cb Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 6 Jan 2022 15:41:02 +0000 Subject: [PATCH 096/478] Replace FALLTHROUGH macro with C++17 [[fallthrough]] attribute See go/chromium-lsc-fallthrough Bug:1283907 Change-Id: I786f3e7141ad47913043136d0173e3b82b223a87 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3370128 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- handler/linux/exception_handler_server.cc | 2 +- snapshot/minidump/process_snapshot_minidump.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index c9fbb0add0..aef252fa4d 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -198,7 +198,7 @@ class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { if (HaveCapSysPtrace()) { return Strategy::kDirectPtrace; } - FALLTHROUGH; + [[fallthrough]]; case PtraceScope::kNoAttach: LOG(WARNING) << "no ptrace"; return Strategy::kNoPtrace; diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index db7e595546..8c870ee005 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -323,7 +323,7 @@ bool ProcessSnapshotMinidump::InitializeMiscInfo() { full_version_ = base::UTF16ToUTF8(info.BuildString); #endif full_version_ = full_version_.substr(0, full_version_.find(';')); - FALLTHROUGH; + [[fallthrough]]; case sizeof(MINIDUMP_MISC_INFO_3): case sizeof(MINIDUMP_MISC_INFO_2): case sizeof(MINIDUMP_MISC_INFO): From 23375ab37c3dee6f442bddbf13b84a15116bcd6e Mon Sep 17 00:00:00 2001 From: Avi Drissman Date: Fri, 7 Jan 2022 17:19:37 -0500 Subject: [PATCH 097/478] Use std::ignore rather than ignore_result in Crashpad Bug: 1285085 Change-Id: I02f1eb608a704fe58b72c094b96af6c7577be4bf Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3373171 Reviewed-by: Mark Mentovai Commit-Queue: Avi Drissman --- DEPS | 2 +- client/crash_report_database_generic.cc | 6 +++--- client/crash_report_database_mac.mm | 7 ++++--- client/crash_report_database_win.cc | 6 +++--- client/crashpad_client_mac.cc | 6 +++--- test/mac/mach_multiprocess.cc | 4 ++-- util/mach/child_port_handshake.h | 4 ++-- util/mach/mach_message_test.cc | 5 +++-- util/posix/close_stdio.cc | 5 +++-- util/stream/file_encoder.cc | 4 ++-- 10 files changed, 26 insertions(+), 23 deletions(-) diff --git a/DEPS b/DEPS index 7bdeef7361..73adbd44f1 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '0243b40af70e34c81fc8a30d9b15cd276b2d49ba', + 'bbb68fcec19ff7c268fadeebd2ef79f7203fa2f2', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index f5dfa891b0..754f578c0b 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/ignore_result.h" #include "base/logging.h" #include "build/build_config.h" #include "client/settings.h" @@ -356,14 +356,14 @@ OperationStatus CrashReportDatabaseGeneric::FinishedWritingCrashReport( return kFileSystemError; } // We've moved the report to pending, so it no longer needs to be removed. - ignore_result(report->file_remover_.release()); + std::ignore = report->file_remover_.release(); // Close all the attachments and disarm their removers too. for (auto& writer : report->attachment_writers_) { writer->Close(); } for (auto& remover : report->attachment_removers_) { - ignore_result(remover.release()); + std::ignore = remover.release(); } *uuid = report->ReportID(); diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index d1c0a3ed2e..52319bef8a 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -25,8 +25,9 @@ #include #include +#include + #include "base/cxx17_backports.h" -#include "base/ignore_result.h" #include "base/logging.h" #include "base/mac/scoped_nsautorelease_pool.h" #include "base/posix/eintr_wrapper.h" @@ -385,14 +386,14 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, PLOG(ERROR) << "rename " << path.value() << " to " << new_path.value(); return kFileSystemError; } - ignore_result(report->file_remover_.release()); + std::ignore = report->file_remover_.release(); // Close all the attachments and disarm their removers too. for (auto& writer : report->attachment_writers_) { writer->Close(); } for (auto& remover : report->attachment_removers_) { - ignore_result(remover.release()); + std::ignore = remover.release(); } Metrics::CrashReportPending(Metrics::PendingReportReason::kNewlyCreated); diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 65feaa4cf4..6331f65082 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -21,9 +21,9 @@ #include #include +#include #include -#include "base/ignore_result.h" #include "base/logging.h" #include "base/numerics/safe_math.h" #include "base/strings/utf_string_conversions.h" @@ -735,14 +735,14 @@ OperationStatus CrashReportDatabaseWin::FinishedWritingCrashReport( time(nullptr), ReportState::kPending)); - ignore_result(report->file_remover_.release()); + std::ignore = report->file_remover_.release(); // Close all the attachments and disarm their removers too. for (auto& writer : report->attachment_writers_) { writer->Close(); } for (auto& remover : report->attachment_removers_) { - ignore_result(remover.release()); + std::ignore = remover.release(); } *uuid = report->ReportID(); diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index b4a365d020..d25bfb7163 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -21,9 +21,9 @@ #include #include +#include #include -#include "base/ignore_result.h" #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/strings/stringprintf.h" @@ -178,7 +178,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { handler_restarter->StartRestartThread( handler, database, metrics_dir, url, annotations, arguments)) { // The thread owns the object now. - ignore_result(handler_restarter.release()); + std::ignore = handler_restarter.release(); } // If StartRestartThread() failed, proceed without the ability to restart. @@ -362,7 +362,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { return false; } - ignore_result(receive_right.release()); + std::ignore = receive_right.release(); return true; } diff --git a/test/mac/mach_multiprocess.cc b/test/mac/mach_multiprocess.cc index 91a06e3acc..5f1b3aca22 100644 --- a/test/mac/mach_multiprocess.cc +++ b/test/mac/mach_multiprocess.cc @@ -19,9 +19,9 @@ #include #include +#include #include "base/auto_reset.h" -#include "base/ignore_result.h" #include "base/mac/scoped_mach_port.h" #include "gtest/gtest.h" #include "test/errors.h" @@ -212,7 +212,7 @@ void MachMultiprocess::MultiprocessChild() { ScopedForbidReturn forbid_return; // local_port is not valid in the forked child process. - ignore_result(info_->local_port.release()); + std::ignore = info_->local_port.release(); info_->local_port.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); ASSERT_NE(info_->local_port, kMachPortNull); diff --git a/util/mach/child_port_handshake.h b/util/mach/child_port_handshake.h index c61f734ed0..54168691bd 100644 --- a/util/mach/child_port_handshake.h +++ b/util/mach/child_port_handshake.h @@ -18,9 +18,9 @@ #include #include +#include #include "base/files/scoped_file.h" -#include "base/ignore_result.h" #include "util/mach/child_port_types.h" namespace crashpad { @@ -124,7 +124,7 @@ class ChildPortHandshakeTest; //! // for use in the parent process. //! if (child_port_handshake.RunClient(receive_right.get(), //! MACH_MSG_TYPE_MOVE_RECEIVE)) { -//! ignore_result(receive_right.release()); +//! std::ignore = receive_right.release(); //! } //! \endcode //! diff --git a/util/mach/mach_message_test.cc b/util/mach/mach_message_test.cc index 0bee04b335..0c578b92d7 100644 --- a/util/mach/mach_message_test.cc +++ b/util/mach/mach_message_test.cc @@ -16,7 +16,8 @@ #include -#include "base/ignore_result.h" +#include + #include "base/mac/scoped_mach_port.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" @@ -154,7 +155,7 @@ TEST(MachMessage, MachMessageDestroyReceivedPort) { ASSERT_EQ(right_type, implicit_cast(MACH_MSG_TYPE_PORT_SEND)); EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_RECEIVE)); - ignore_result(receive.release()); + std::ignore = receive.release(); EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND)); } diff --git a/util/posix/close_stdio.cc b/util/posix/close_stdio.cc index a8efc81c19..37c40a4a0a 100644 --- a/util/posix/close_stdio.cc +++ b/util/posix/close_stdio.cc @@ -18,9 +18,10 @@ #include #include +#include + #include "base/check.h" #include "base/files/scoped_file.h" -#include "base/ignore_result.h" #include "base/posix/eintr_wrapper.h" namespace crashpad { @@ -32,7 +33,7 @@ void CloseStdioStream(int desired_fd, int oflag) { HANDLE_EINTR(open(_PATH_DEVNULL, oflag | O_NOCTTY | O_CLOEXEC))); if (fd == desired_fd) { // Weird, but play along. - ignore_result(fd.release()); + std::ignore = fd.release(); } else { PCHECK(fd.get() >= 0) << "open"; PCHECK(HANDLE_EINTR(dup2(fd.get(), desired_fd)) != -1) << "dup2"; diff --git a/util/stream/file_encoder.cc b/util/stream/file_encoder.cc index 5cebbfcc52..d39b5b09a5 100644 --- a/util/stream/file_encoder.cc +++ b/util/stream/file_encoder.cc @@ -15,8 +15,8 @@ #include "util/stream/file_encoder.h" #include +#include -#include "base/ignore_result.h" #include "util/file/file_io.h" #include "util/file/file_reader.h" #include "util/file/scoped_remove_file.h" @@ -77,7 +77,7 @@ bool FileEncoder::Process() { if (!output->Flush()) return false; - ignore_result(file_remover.release()); + std::ignore = file_remover.release(); return true; } From b560edd484323f00ef99c975acb6cc1ddd128ca1 Mon Sep 17 00:00:00 2001 From: Avi Drissman Date: Fri, 14 Jan 2022 17:51:32 -0500 Subject: [PATCH 098/478] Remove ALLOW_UNUSED_LOCAL from Crashpad Bug: 1286390 Change-Id: I9755258960c55bef84e01812a14067ffaf89d2b1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3388879 Commit-Queue: Avi Drissman Reviewed-by: Mark Mentovai --- DEPS | 2 +- handler/handler_main.cc | 8 ++--- minidump/minidump_misc_info_writer_test.cc | 7 ++--- minidump/minidump_string_writer_test.cc | 7 ++--- minidump/minidump_system_info_writer_test.cc | 4 +-- util/misc/arraysize_test.cc | 31 +++++++------------- util/misc/initialization_state_dcheck.h | 9 +++--- util/misc/scoped_forbid_return_test.cc | 10 +++---- util/posix/signals_test.cc | 4 +-- util/stdlib/aligned_allocator_test.cc | 11 +++---- 10 files changed, 33 insertions(+), 60 deletions(-) diff --git a/DEPS b/DEPS index 73adbd44f1..8f9617f404 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'bbb68fcec19ff7c268fadeebd2ef79f7203fa2f2', + 'c2bc7a2a195eb8940215d0b81767f022aa5ecfdd', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 5733463bed..5e8ff1a2d2 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -28,7 +28,6 @@ #include #include "base/auto_reset.h" -#include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/files/scoped_file.h" #include "base/logging.h" @@ -252,11 +251,10 @@ bool AddKeyValueToMap(std::map* map, // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after // something else logs an exit event. void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { - static bool once = [](Metrics::LifetimeMilestone milestone) { + [[maybe_unused]] static bool once = [](Metrics::LifetimeMilestone milestone) { Metrics::HandlerLifetimeMilestone(milestone); return true; }(milestone); - ALLOW_UNUSED_LOCAL(once); } // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for @@ -422,8 +420,8 @@ void InstallCrashHandler() { // enough. Note that destroying the TerminateHandler would wait for its thread // to exit, which isn’t necessary or desirable. SetConsoleCtrlHandler(ConsoleHandler, true); - static TerminateHandler* terminate_handler = new TerminateHandler(); - ALLOW_UNUSED_LOCAL(terminate_handler); + [[maybe_unused]] static TerminateHandler* terminate_handler = + new TerminateHandler(); } #endif // OS_APPLE diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index 18ac2966bb..f74d0bd5df 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -19,7 +19,6 @@ #include #include -#include "base/compiler_specific.h" #include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" @@ -436,8 +435,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { constexpr uint32_t kTimeZoneId = 2; constexpr int32_t kBias = 300; - MINIDUMP_MISC_INFO_N tmp; - ALLOW_UNUSED_LOCAL(tmp); + [[maybe_unused]] MINIDUMP_MISC_INFO_N tmp; std::string standard_name(base::size(tmp.TimeZone.StandardName) + 1, 's'); constexpr int32_t kStandardBias = 0; std::string daylight_name(base::size(tmp.TimeZone.DaylightName), 'd'); @@ -528,8 +526,7 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = std::make_unique(); - MINIDUMP_MISC_INFO_N tmp; - ALLOW_UNUSED_LOCAL(tmp); + [[maybe_unused]] MINIDUMP_MISC_INFO_N tmp; std::string build_string(base::size(tmp.BuildString) + 1, 'B'); std::string debug_build_string(base::size(tmp.DbgBldStr), 'D'); diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index bfaf3a9aef..9609ade11f 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -16,7 +16,6 @@ #include -#include "base/compiler_specific.h" #include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" @@ -86,8 +85,7 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { const size_t expected_utf16_units_with_nul = kTestData[index].output_length + 1; - MINIDUMP_STRING* tmp; - ALLOW_UNUSED_LOCAL(tmp); + [[maybe_unused]] MINIDUMP_STRING* tmp; const size_t expected_utf16_bytes = expected_utf16_units_with_nul * sizeof(tmp->Buffer[0]); ASSERT_EQ(string_file.string().size(), sizeof(*tmp) + expected_utf16_bytes); @@ -130,8 +128,7 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { const MINIDUMP_STRING* minidump_string = MinidumpStringAtRVA(string_file.string(), 0); EXPECT_TRUE(minidump_string); - MINIDUMP_STRING* tmp; - ALLOW_UNUSED_LOCAL(tmp); + [[maybe_unused]] MINIDUMP_STRING* tmp; EXPECT_EQ( minidump_string->Length, string_file.string().size() - sizeof(*tmp) - sizeof(tmp->Buffer[0])); diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 206a8e41cc..81de730bd0 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -20,7 +20,6 @@ #include #include -#include "base/compiler_specific.h" #include "gtest/gtest.h" #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" @@ -39,8 +38,7 @@ void GetSystemInfoStream(const std::string& file_contents, const MINIDUMP_SYSTEM_INFO** system_info, const MINIDUMP_STRING** csd_version) { // The expected number of bytes for the CSD version’s MINIDUMP_STRING::Buffer. - MINIDUMP_STRING* tmp; - ALLOW_UNUSED_LOCAL(tmp); + [[maybe_unused]] MINIDUMP_STRING* tmp; const size_t kCSDVersionBytes = csd_version_length * sizeof(tmp->Buffer[0]); const size_t kCSDVersionBytesWithNUL = kCSDVersionBytes + sizeof(tmp->Buffer[0]); diff --git a/util/misc/arraysize_test.cc b/util/misc/arraysize_test.cc index ad8da0970a..5a2106a092 100644 --- a/util/misc/arraysize_test.cc +++ b/util/misc/arraysize_test.cc @@ -14,7 +14,6 @@ #include "util/misc/arraysize.h" -#include "base/compiler_specific.h" #include "gtest/gtest.h" namespace crashpad { @@ -22,37 +21,29 @@ namespace test { namespace { TEST(ArraySize, ArraySize) { - char c1[1]; + [[maybe_unused]] char c1[1]; static_assert(ArraySize(c1) == 1, "c1"); - ALLOW_UNUSED_LOCAL(c1); - char c2[2]; + [[maybe_unused]] char c2[2]; static_assert(ArraySize(c2) == 2, "c2"); - ALLOW_UNUSED_LOCAL(c2); - char c4[4]; + [[maybe_unused]] char c4[4]; static_assert(ArraySize(c4) == 4, "c4"); - ALLOW_UNUSED_LOCAL(c4); - int i1[1]; + [[maybe_unused]] int i1[1]; static_assert(ArraySize(i1) == 1, "i1"); - ALLOW_UNUSED_LOCAL(i1); - int i2[2]; + [[maybe_unused]] int i2[2]; static_assert(ArraySize(i2) == 2, "i2"); - ALLOW_UNUSED_LOCAL(i2); - int i4[4]; + [[maybe_unused]] int i4[4]; static_assert(ArraySize(i4) == 4, "i4"); - ALLOW_UNUSED_LOCAL(i4); - long l8[8]; + [[maybe_unused]] long l8[8]; static_assert(ArraySize(l8) == 8, "l8"); - ALLOW_UNUSED_LOCAL(l8); - int l9[9]; + [[maybe_unused]] int l9[9]; static_assert(ArraySize(l9) == 9, "l9"); - ALLOW_UNUSED_LOCAL(l9); struct S { char c; @@ -61,13 +52,11 @@ TEST(ArraySize, ArraySize) { bool b; }; - S s1[1]; + [[maybe_unused]] S s1[1]; static_assert(ArraySize(s1) == 1, "s1"); - ALLOW_UNUSED_LOCAL(s1); - S s10[10]; + [[maybe_unused]] S s10[10]; static_assert(ArraySize(s10) == 10, "s10"); - ALLOW_UNUSED_LOCAL(s10); } } // namespace diff --git a/util/misc/initialization_state_dcheck.h b/util/misc/initialization_state_dcheck.h index e04ff234c3..51220d513d 100644 --- a/util/misc/initialization_state_dcheck.h +++ b/util/misc/initialization_state_dcheck.h @@ -17,8 +17,9 @@ //! \file +#include + #include "base/check_op.h" -#include "base/compiler_specific.h" #include "build/build_config.h" #include "util/misc/initialization_state.h" @@ -175,11 +176,11 @@ using InitializationStateDcheck = bool[0]; // Avoid triggering warnings by repurposing these macros when DCHECKs are // disabled. #define INITIALIZATION_STATE_SET_INITIALIZING(initialization_state_dcheck) \ - ALLOW_UNUSED_LOCAL(initialization_state_dcheck) + do { std::ignore = initialization_state_dcheck; } while (false) #define INITIALIZATION_STATE_SET_VALID(initialization_state_dcheck) \ - ALLOW_UNUSED_LOCAL(initialization_state_dcheck) + do { std::ignore = initialization_state_dcheck; } while (false) #define INITIALIZATION_STATE_DCHECK_VALID(initialization_state_dcheck) \ - ALLOW_UNUSED_LOCAL(initialization_state_dcheck) + do { std::ignore = initialization_state_dcheck; } while (false) #endif diff --git a/util/misc/scoped_forbid_return_test.cc b/util/misc/scoped_forbid_return_test.cc index 06cb5494b4..b728cf4dc7 100644 --- a/util/misc/scoped_forbid_return_test.cc +++ b/util/misc/scoped_forbid_return_test.cc @@ -14,7 +14,6 @@ #include "util/misc/scoped_forbid_return.h" -#include "base/compiler_specific.h" #include "gtest/gtest.h" #include "test/gtest_death.h" @@ -43,13 +42,12 @@ void ScopedForbidReturnHelper(ForbidReturnType type) { } } -constexpr char kForbiddenMessage[] = "attempt to exit scope forbidden"; +// kForbiddenMessage may appear to be unused if ASSERT_DEATH_CHECK() throws it +// away. +[[maybe_unused]] constexpr char kForbiddenMessage[] = + "attempt to exit scope forbidden"; TEST(ScopedForbidReturnDeathTest, Default) { - // kForbiddenMessage may appear to be unused if ASSERT_DEATH_CHECK() throws it - // away. - ALLOW_UNUSED_LOCAL(kForbiddenMessage); - ASSERT_DEATH_CHECK(ScopedForbidReturnHelper(kForbidReturnDefault), kForbiddenMessage); } diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index cb29ff50b3..769483c40d 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -22,7 +22,6 @@ #include -#include "base/compiler_specific.h" #include "base/cxx17_backports.h" #include "base/files/scoped_file.h" #include "base/logging.h" @@ -163,10 +162,9 @@ void CauseSignal(int sig, int code) { * Arm architecture. */ #if defined(ARCH_CPU_X86_FAMILY) - volatile int a = 42; + [[maybe_unused]] volatile int a = 42; volatile int b = 0; a /= b; - ALLOW_UNUSED_LOCAL(a); #endif break; } diff --git a/util/stdlib/aligned_allocator_test.cc b/util/stdlib/aligned_allocator_test.cc index 1c16dcc5e0..e44494ba94 100644 --- a/util/stdlib/aligned_allocator_test.cc +++ b/util/stdlib/aligned_allocator_test.cc @@ -16,7 +16,6 @@ #include -#include "base/compiler_specific.h" #include "gtest/gtest.h" #include "test/gtest_death.h" @@ -93,12 +92,10 @@ TEST(AlignedAllocator, AlignedVector) { void BadAlignmentTest() { #if defined(OS_WIN) // Suppress the assertion MessageBox() normally displayed by the CRT in debug - // mode. - int previous = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); - - // In release mode, _CrtSetReportMode() is #defined to ((int)0), so |previous| - // would appear unused. - ALLOW_UNUSED_LOCAL(previous); + // mode. In release mode, _CrtSetReportMode() is #defined to ((int)0), so + // |previous| would appear unused, thus the [[maybe_unused]]. + [[maybe_unused]] int previous = + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); #endif // Alignment constraints must be powers of 2. 7 is not valid. From 824ddb2de14b47f5a283e52e3e53e6bd795a9a2f Mon Sep 17 00:00:00 2001 From: Avi Drissman Date: Fri, 14 Jan 2022 18:25:31 -0500 Subject: [PATCH 099/478] Fix presubmit issues - Formatted util/misc/initialization_state_dcheck.h - Included build/build_config.h file in util/stdlib/aligned_allocator_test.cc as it uses an OS_* macro. Change-Id: I8fb67f1ae440834d1b60f390658513a341789428 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3390648 Reviewed-by: Mark Mentovai Commit-Queue: Avi Drissman --- util/misc/initialization_state_dcheck.h | 12 +++++++++--- util/stdlib/aligned_allocator_test.cc | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/util/misc/initialization_state_dcheck.h b/util/misc/initialization_state_dcheck.h index 51220d513d..659eaa8457 100644 --- a/util/misc/initialization_state_dcheck.h +++ b/util/misc/initialization_state_dcheck.h @@ -176,11 +176,17 @@ using InitializationStateDcheck = bool[0]; // Avoid triggering warnings by repurposing these macros when DCHECKs are // disabled. #define INITIALIZATION_STATE_SET_INITIALIZING(initialization_state_dcheck) \ - do { std::ignore = initialization_state_dcheck; } while (false) + do { \ + std::ignore = initialization_state_dcheck; \ + } while (false) #define INITIALIZATION_STATE_SET_VALID(initialization_state_dcheck) \ - do { std::ignore = initialization_state_dcheck; } while (false) + do { \ + std::ignore = initialization_state_dcheck; \ + } while (false) #define INITIALIZATION_STATE_DCHECK_VALID(initialization_state_dcheck) \ - do { std::ignore = initialization_state_dcheck; } while (false) + do { \ + std::ignore = initialization_state_dcheck; \ + } while (false) #endif diff --git a/util/stdlib/aligned_allocator_test.cc b/util/stdlib/aligned_allocator_test.cc index e44494ba94..40e14e83fa 100644 --- a/util/stdlib/aligned_allocator_test.cc +++ b/util/stdlib/aligned_allocator_test.cc @@ -16,6 +16,7 @@ #include +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/gtest_death.h" From 243e1fd8e2f856209a24ca91090c837be87a1993 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 14 Jan 2022 22:25:59 -0500 Subject: [PATCH 100/478] ios: Set EXC_SOFT_SIGNAL for signal exceptions. Right now there's no clear way to differentiate between Signal and Mach exceptions. Instead, set EXC_SOFT_SIGNAL as the top level exception for signal exceptions, moving the signal number to ExceptionInfo() and and the signal code plus the two previous values into Codes(). Fixed:crashpad:389 Change-Id: Ia57f402b98be2a648febb58b9dee0cb80d9e5954 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3388874 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- ...xception_snapshot_ios_intermediate_dump.cc | 10 ++- test/ios/crash_type_xctest.mm | 68 ++++++++++++----- test/ios/host/cptest_application_delegate.mm | 73 ++++++++++--------- test/ios/host/cptest_shared_object.h | 12 ++- 4 files changed, 106 insertions(+), 57 deletions(-) diff --git a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc index c4d99e77a6..a45d4cc290 100644 --- a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc @@ -131,10 +131,16 @@ bool ExceptionSnapshotIOSIntermediateDump::InitializeFromSignal( #endif } - GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_); - GetDataValueFromMap(exception_data, Key::kSignalCode, &exception_info_); + exception_ = EXC_SOFT_SIGNAL; + GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_info_); GetDataValueFromMap(exception_data, Key::kSignalAddress, &exception_address_); + codes_.push_back(exception_); + codes_.push_back(exception_info_); + uint32_t code; + GetDataValueFromMap(exception_data, Key::kSignalCode, &code); + codes_.push_back(code); + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 2dcfac786f..3613e220ec 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -65,7 +65,7 @@ - (void)setUp { XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); } -- (void)verifyCrashReportException:(int)exception { +- (void)verifyCrashReportException:(uint32_t)exception { // Confirm the app is not running. XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); @@ -75,7 +75,9 @@ - (void)verifyCrashReportException:(int)exception { XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); rootObject_ = [EDOClientService rootObjectWithPort:12345]; XCTAssertEqual([rootObject_ pendingReportCount], 1); - XCTAssertEqual([rootObject_ pendingReportException], exception); + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportException:&report_exception]); + XCTAssertEqual(report_exception.unsignedIntValue, exception); } - (void)testEDO { @@ -85,44 +87,61 @@ - (void)testEDO { - (void)testSegv { [rootObject_ crashSegv]; -#if defined(NDEBUG) && TARGET_OS_SIMULATOR - [self verifyCrashReportException:SIGINT]; +#if defined(NDEBUG) +#if TARGET_OS_SIMULATOR + [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; +#else + [self verifyCrashReportException:EXC_BREAKPOINT]; +#endif #else - [self verifyCrashReportException:SIGHUP]; + [self verifyCrashReportException:EXC_BAD_ACCESS]; #endif } - (void)testKillAbort { [rootObject_ crashKillAbort]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); } - (void)testTrap { [rootObject_ crashTrap]; #if TARGET_OS_SIMULATOR - [self verifyCrashReportException:SIGINT]; + [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; #else - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_BREAKPOINT]; #endif } - (void)testAbort { [rootObject_ crashAbort]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); } - (void)testBadAccess { [rootObject_ crashBadAccess]; -#if defined(NDEBUG) && TARGET_OS_SIMULATOR - [self verifyCrashReportException:SIGINT]; +#if defined(NDEBUG) +#if TARGET_OS_SIMULATOR + [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; #else - [self verifyCrashReportException:SIGHUP]; + [self verifyCrashReportException:EXC_BREAKPOINT]; +#endif +#else + [self verifyCrashReportException:EXC_BAD_ACCESS]; #endif } - (void)testException { [rootObject_ crashException]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); } - (void)testNSException { @@ -183,7 +202,7 @@ - (void)testCrashCoreAutoLayoutSinkhole { - (void)testRecursion { [rootObject_ crashRecursion]; - [self verifyCrashReportException:SIGHUP]; + [self verifyCrashReportException:EXC_BAD_ACCESS]; } - (void)testClientAnnotations { @@ -192,7 +211,11 @@ - (void)testClientAnnotations { // Set app launch args to trigger different client annotations. NSArray* old_args = app_.launchArguments; app_.launchArguments = @[ @"--alternate-client-annotations" ]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); + app_.launchArguments = old_args; // Confirm the initial crash took the standard annotations. @@ -205,7 +228,10 @@ - (void)testClientAnnotations { // Confirm passing alternate client annotation args works. [rootObject_ clearPendingReports]; [rootObject_ crashKillAbort]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); + dict = [rootObject_ getProcessAnnotations]; XCTAssertTrue([dict[@"crashpad"] isEqualToString:@"no"]); XCTAssertTrue([dict[@"plat"] isEqualToString:@"macOS"]); @@ -220,7 +246,7 @@ - (void)testCrashWithCrashInfoMessage { return; } [rootObject_ crashWithCrashInfoMessage]; - [self verifyCrashReportException:SIGHUP]; + [self verifyCrashReportException:EXC_BAD_ACCESS]; NSDictionary* dict = [rootObject_ getAnnotations]; NSString* dyldMessage = dict[@"vector"][0]; XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]); @@ -235,7 +261,7 @@ - (void)testCrashWithDyldErrorString { return; } [rootObject_ crashWithDyldErrorString]; - [self verifyCrashReportException:SIGINT]; + [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; NSArray* vector = [rootObject_ getAnnotations][@"vector"]; // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp // ImageLoaderMachO::doInitialization(). @@ -246,7 +272,11 @@ - (void)testCrashWithDyldErrorString { - (void)testCrashWithAnnotations { [rootObject_ crashWithAnnotations]; - [self verifyCrashReportException:SIGABRT]; + [self verifyCrashReportException:EXC_SOFT_SIGNAL]; + NSNumber* report_exception; + XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]); + XCTAssertEqual(report_exception.intValue, SIGABRT); + NSDictionary* dict = [rootObject_ getAnnotations]; NSDictionary* simpleMap = dict[@"simplemap"]; XCTAssertTrue([simpleMap[@"#TEST# empty_value"] isEqualToString:@""]); diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 44a7d88ad8..3bf39dfec0 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -68,6 +68,24 @@ OperationStatus GetPendingReports(std::vector* pending_reports) { return database->GetPendingReports(pending_reports); } +std::unique_ptr +GetProcessSnapshotMinidumpFromSinglePending() { + std::vector pending_reports; + OperationStatus status = GetPendingReports(&pending_reports); + if (status != crashpad::CrashReportDatabase::kNoError || + pending_reports.size() != 1) { + return nullptr; + } + + auto reader = std::make_unique(); + auto process_snapshot = std::make_unique(); + if (!reader->Open(pending_reports[0].file_path) || + !process_snapshot->Initialize(reader.get())) { + return nullptr; + } + return process_snapshot; +} + [[clang::optnone]] void recurse(int counter) { // Fill up the stack faster. int arr[1024]; @@ -159,40 +177,36 @@ - (int)pendingReportCount { return pending_reports.size(); } -- (int)pendingReportException { - std::vector pending_reports; - OperationStatus status = GetPendingReports(&pending_reports); - if (status != crashpad::CrashReportDatabase::kNoError || - pending_reports.size() != 1) { - return -1; - } +- (bool)pendingReportException:(NSNumber**)exception { + auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending(); + if (!process_snapshot || !process_snapshot->Exception()->Exception()) + return false; + *exception = [NSNumber + numberWithUnsignedInt:process_snapshot->Exception()->Exception()]; + return true; +} - auto reader = std::make_unique(); - reader->Open(pending_reports[0].file_path); - crashpad::ProcessSnapshotMinidump process_snapshot; - process_snapshot.Initialize(reader.get()); - return static_cast(process_snapshot.Exception()->Exception()); +- (bool)pendingReportExceptionInfo:(NSNumber**)exception_info { + auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending(); + if (!process_snapshot || !process_snapshot->Exception()->ExceptionInfo()) + return false; + + *exception_info = [NSNumber + numberWithUnsignedInt:process_snapshot->Exception()->ExceptionInfo()]; + return true; } - (NSDictionary*)getAnnotations { - std::vector pending_reports; - OperationStatus status = GetPendingReports(&pending_reports); - if (status != crashpad::CrashReportDatabase::kNoError || - pending_reports.size() != 1) { + auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending(); + if (!process_snapshot) return @{}; - } - - auto reader = std::make_unique(); - reader->Open(pending_reports[0].file_path); - crashpad::ProcessSnapshotMinidump process_snapshot; - process_snapshot.Initialize(reader.get()); NSDictionary* dict = @{ @"simplemap" : [@{} mutableCopy], @"vector" : [@[] mutableCopy], @"objects" : [@[] mutableCopy] }; - for (const auto* module : process_snapshot.Modules()) { + for (const auto* module : process_snapshot->Modules()) { for (const auto& kv : module->AnnotationsSimpleMap()) { [dict[@"simplemap"] setValue:@(kv.second.c_str()) forKey:@(kv.first.c_str())]; @@ -215,19 +229,12 @@ - (NSDictionary*)getAnnotations { } - (NSDictionary*)getProcessAnnotations { - std::vector pending_reports; - OperationStatus status = GetPendingReports(&pending_reports); - if (status != crashpad::CrashReportDatabase::kNoError || - pending_reports.size() != 1) { + auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending(); + if (!process_snapshot) return @{}; - } - auto reader = std::make_unique(); - reader->Open(pending_reports[0].file_path); - crashpad::ProcessSnapshotMinidump process_snapshot; - process_snapshot.Initialize(reader.get()); NSDictionary* dict = [@{} mutableCopy]; - for (const auto& kv : process_snapshot.AnnotationsSimpleMap()) { + for (const auto& kv : process_snapshot->AnnotationsSimpleMap()) { [dict setValue:@(kv.second.c_str()) forKey:@(kv.first.c_str())]; } diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index bcd755479d..90e3de8d38 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -32,9 +32,15 @@ // report. - (int)pendingReportCount; -// Returns exception code when there's a single pending report, or -1 if there's -// a different number of pending reports. -- (int)pendingReportException; +// Returns true if there's a single pending report and sets the exception code +// in the out |exception| parameter. Returns false if there's a different number +// of pending reports. +- (bool)pendingReportException:(NSNumber**)exception; + +// Returns true if there's a single pending report and sets the second-level +// exception code in the out |exception_info| parameter. Returns false if +// there's a different number of pending reports. +- (bool)pendingReportExceptionInfo:(NSNumber**)exception_info; // Return an NSDictionary with a dictionary named "simplemap", an array named // "vector" and an array named "objects", representing the combination of all From 9ed7e84644239886a26669551bac72af24b98a1c Mon Sep 17 00:00:00 2001 From: Aleksey Khoroshilov Date: Tue, 18 Jan 2022 23:36:01 +0700 Subject: [PATCH 101/478] MacOS, iOS: Replace dynamic comments in mig-generated files with stable ones. Mig-generated files contain mig identifiers, which include timestamp and mig build info. To improve build determinism and goma cachehits we can replace these lines with something stable. Bug: crashpad:390 Change-Id: Iedb2f6e64428612899587c2ac4d488baf439961f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3394052 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- util/mach/mig_fix.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/util/mach/mig_fix.py b/util/mach/mig_fix.py index 037746fac3..6e2877136a 100755 --- a/util/mach/mig_fix.py +++ b/util/mach/mig_fix.py @@ -23,6 +23,33 @@ from mig_gen import MigInterface +def _make_generated_comments_deterministic(contents): + """Replaces generated code comments with determenistic ones. + + This is what is generated by mig (only in .c files): + /* + * IDENTIFICATION: + * stub generated Mon Jan 17 15:28:03 2022 + * with a MiG generated by bootstrap_cmds-122 + * OPTIONS: + */ + + We look for two specific lines and replace them like so: + /* + * IDENTIFICATION: + * stub generated + * with a MiG generated by + * OPTIONS: + */ + """ + + return re.sub(r'^( \* (?:stub generated|with a MiG generated by) ).+$', + r'\1', + contents, + count=2, + flags=re.MULTILINE) + + def _fix_user_implementation(implementation, fixed_implementation, header, fixed_header): """Rewrites a MIG-generated user implementation (.c) file. @@ -33,7 +60,8 @@ def _fix_user_implementation(implementation, fixed_implementation, header, unused in the user implementation file, and this will trigger a -Wunused-local-typedefs warning in gcc unless removed or marked with the “unused” attribute. Also changes header references to point to the new - header filename, if changed. + header filename, if changed. Replaces generated code comments with + deterministic ones. If |fixed_implementation| is None, overwrites the original; otherwise, puts the result in the file at |fixed_implementation|. @@ -50,6 +78,9 @@ def _fix_user_implementation(implementation, fixed_implementation, header, '#include "%s"' % os.path.basename(header), '#include "%s"' % os.path.basename(fixed_header)) + # Replace generated code comments with determenistic ones. + contents = _make_generated_comments_deterministic(contents) + if fixed_implementation is None: file.seek(0) file.truncate() @@ -71,6 +102,7 @@ def _fix_server_implementation(implementation, fixed_implementation, header, added to a header file, so that other files that include that header file will have access to these declarations from a compilation perspective. Also changes header references to point to the new header filename, if changed. + Replaces generated code comments with deterministic ones. If |fixed_implementation| is None or not provided, overwrites the original; otherwise, puts the result in the file at |fixed_implementation|. @@ -117,6 +149,9 @@ def _fix_server_implementation(implementation, fixed_implementation, header, '#include "%s"' % os.path.basename(header), '#include "%s"' % os.path.basename(fixed_header)) + # Replace generated code comments with determenistic ones. + contents = _make_generated_comments_deterministic(contents) + if fixed_implementation is None: file.seek(0) file.truncate() From b714b223ad7fdd75bd9278c9a7d005df3954d119 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 18 Jan 2022 18:40:10 -0500 Subject: [PATCH 102/478] ios: Actually merge memory snapshot data. To avoid unnecessary duplication of potentially large memory regions, the iOS MemorySnapshot data is owned by the intermediate dump. When merging two iOS memory snapshots, it's necessary to copy the merged data into a vector owned by the memory snapshot itself. Previously the merged snapshot just contained the original data, which leads to a heap overrun. Bug: 1288544 Change-Id: I4eb392800141451db188d17c7b9f9ca9bd3bb603 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3399252 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- .../memory_snapshot_ios_intermediate_dump.cc | 25 +++++++++++++++++++ .../memory_snapshot_ios_intermediate_dump.h | 8 ++++++ 2 files changed, 33 insertions(+) diff --git a/snapshot/ios/memory_snapshot_ios_intermediate_dump.cc b/snapshot/ios/memory_snapshot_ios_intermediate_dump.cc index 8e521d904f..84275aa918 100644 --- a/snapshot/ios/memory_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/memory_snapshot_ios_intermediate_dump.cc @@ -50,12 +50,37 @@ bool MemorySnapshotIOSIntermediateDump::Read(Delegate* delegate) const { const MemorySnapshot* MemorySnapshotIOSIntermediateDump::MergeWithOtherSnapshot( const MemorySnapshot* other) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + auto other_snapshot = + reinterpret_cast(other); + + INITIALIZATION_STATE_DCHECK_VALID(other_snapshot->initialized_); + if (other_snapshot->address_ < address_) { + return other_snapshot->MergeWithOtherSnapshot(this); + } + CheckedRange merged(0, 0); if (!LoggingDetermineMergedRange(this, other, &merged)) return nullptr; auto result = std::make_unique(); result->Initialize(merged.base(), data_, merged.size()); + if (size_ == merged.size()) { + return result.release(); + } + + const uint8_t* data = reinterpret_cast(data_); + const uint8_t* other_data = + reinterpret_cast(other_snapshot->data_); + vm_size_t overlap = merged.size() - other_snapshot->size_; + result->merged_data_.reserve(merged.size()); + result->merged_data_.insert(result->merged_data_.end(), data, data + overlap); + result->merged_data_.insert(result->merged_data_.end(), + other_data, + other_data + other_snapshot->size_); + result->data_ = + reinterpret_cast(result->merged_data_.data()); + DCHECK_EQ(result->merged_data_.size(), merged.size()); return result.release(); } diff --git a/snapshot/ios/memory_snapshot_ios_intermediate_dump.h b/snapshot/ios/memory_snapshot_ios_intermediate_dump.h index a93200020c..244bbd8be4 100644 --- a/snapshot/ios/memory_snapshot_ios_intermediate_dump.h +++ b/snapshot/ios/memory_snapshot_ios_intermediate_dump.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_SNAPSHOT_IOS_INTERMEDIATE_DUMP_MEMORY_SNAPSHOT_IOS_INTERMEDIATEDUMP_H_ #define CRASHPAD_SNAPSHOT_IOS_INTERMEDIATE_DUMP_MEMORY_SNAPSHOT_IOS_INTERMEDIATEDUMP_H_ +#include + #include "snapshot/memory_snapshot.h" #include "util/misc/address_types.h" #include "util/misc/initialization_state_dcheck.h" @@ -55,6 +57,12 @@ class MemorySnapshotIOSIntermediateDump final : public MemorySnapshot { vm_address_t address_; vm_address_t data_; + + // Because the iOS snapshot memory region is owned by the intermediate dump, + // it's necessary to copy the merged data into a vector owned by the memory + // snapshot itself. + std::vector merged_data_; + vm_size_t size_; InitializationStateDcheck initialized_; }; From 50ed179e9a66937857acf7bc5eba356500f8b122 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 19 Jan 2022 15:00:24 -0500 Subject: [PATCH 103/478] Use BUILDFLAG for OS checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza Commit-Queue: Mark Mentovai --- DEPS | 2 +- client/annotation.h | 6 +- client/annotation_list.h | 4 +- client/crash_report_database.cc | 8 +- client/crash_report_database_generic.cc | 2 +- client/crash_report_database_test.cc | 10 +- client/crashpad_client.h | 38 ++- client/crashpad_client_linux.cc | 12 +- client/crashpad_client_linux_test.cc | 9 +- client/crashpad_info.cc | 17 +- client/crashpad_info.h | 8 +- client/settings.cc | 9 +- client/settings.h | 6 +- client/settings_test.cc | 2 +- client/simulate_crash.h | 8 +- handler/crash_report_upload_thread.cc | 16 +- handler/crash_report_upload_thread.h | 5 +- .../crashpad_handler_test_extended_handler.cc | 8 +- handler/handler_main.cc | 294 ++++++++++-------- handler/handler_main.h | 2 +- .../linux/crash_report_exception_handler.cc | 4 +- .../linux/exception_handler_server_test.cc | 2 +- handler/main.cc | 8 +- minidump/minidump_context_writer.cc | 5 +- minidump/minidump_file_writer_test.cc | 9 +- minidump/minidump_misc_info_writer.cc | 24 +- snapshot/crashpad_info_client_options_test.cc | 26 +- ...rashpad_info_client_options_test_module.cc | 10 +- snapshot/crashpad_info_size_test_module.cc | 29 +- .../crashpad_types/crashpad_info_reader.cc | 6 +- .../crashpad_info_reader_test.cc | 4 +- .../image_annotation_reader_test.cc | 4 +- snapshot/elf/elf_image_reader.cc | 4 +- snapshot/elf/elf_image_reader_test.cc | 23 +- snapshot/linux/debug_rendezvous.cc | 6 +- snapshot/linux/debug_rendezvous_test.cc | 14 +- snapshot/linux/process_reader_linux.cc | 10 +- snapshot/linux/process_reader_linux_test.cc | 15 +- snapshot/linux/process_snapshot_linux.cc | 3 +- snapshot/linux/signal_context.h | 4 +- snapshot/linux/system_snapshot_linux.cc | 19 +- snapshot/linux/system_snapshot_linux_test.cc | 4 +- snapshot/posix/timezone.cc | 6 +- .../process_snapshot_sanitized_test.cc | 2 +- .../sanitization_information_test.cc | 2 +- snapshot/x86/cpuid_reader.cc | 13 +- test/errors.cc | 10 +- test/errors.h | 2 +- test/file.cc | 8 +- test/filesystem.cc | 37 +-- test/filesystem.h | 4 +- test/gtest_death.h | 8 +- test/gtest_main.cc | 32 +- test/multiprocess.h | 18 +- test/multiprocess_exec.cc | 3 +- test/multiprocess_exec.h | 6 +- test/multiprocess_exec_posix.cc | 8 +- test/multiprocess_exec_test.cc | 4 +- test/multiprocess_exec_test_child.cc | 18 +- test/multiprocess_posix.cc | 12 +- test/process_type.cc | 14 +- test/process_type.h | 18 +- test/scoped_module_handle.cc | 5 +- test/scoped_module_handle.h | 8 +- test/scoped_temp_dir_posix.cc | 2 +- test/scoped_temp_dir_test.cc | 14 +- test/test_paths.cc | 56 ++-- test/test_paths.h | 8 +- tools/base94_encoder.cc | 8 +- tools/crashpad_database_util.cc | 8 +- tools/crashpad_http_upload.cc | 9 +- tools/generate_dump.cc | 38 +-- tools/mac/catch_exception_tool.cc | 2 + tools/mac/exception_port_tool.cc | 2 + tools/mac/on_demand_service_tool.mm | 2 + tools/run_with_crashpad.cc | 14 +- tools/tool_support.cc | 21 +- tools/tool_support.h | 8 +- util/file/directory_reader.h | 14 +- util/file/directory_reader_test.cc | 13 +- util/file/file_io.h | 20 +- util/file/file_io_posix.cc | 10 +- util/file/file_io_test.cc | 13 +- util/file/file_writer.cc | 18 +- util/file/file_writer.h | 3 +- util/file/filesystem_posix.cc | 4 +- util/file/filesystem_test.cc | 38 +-- util/linux/auxiliary_vector_test.cc | 4 +- util/linux/exception_handler_client.cc | 2 +- util/linux/exception_handler_protocol.cc | 12 +- util/linux/exception_handler_protocol.h | 2 +- util/linux/memory_map.cc | 10 +- util/linux/memory_map_test.cc | 18 +- util/linux/thread_info.h | 7 +- util/mach/exc_server_variants.cc | 4 +- util/mach/exc_server_variants_test.cc | 10 +- util/mach/mach_extensions.cc | 12 +- util/mach/mach_extensions_test.cc | 12 +- util/mach/mach_message.cc | 9 +- util/mach/mach_message.h | 4 +- util/mach/mach_message_test.cc | 5 +- util/misc/address_types.h | 16 +- util/misc/capture_context.h | 20 +- util/misc/capture_context_test.cc | 4 +- util/misc/clock_posix.cc | 2 +- util/misc/clock_test.cc | 9 +- util/misc/metrics.cc | 12 +- util/misc/metrics.h | 4 +- util/misc/no_cfi_icall.h | 18 +- util/misc/no_cfi_icall_test.cc | 6 +- util/misc/time.h | 12 +- util/misc/time_test.cc | 9 +- util/misc/uuid.cc | 23 +- util/misc/uuid.h | 14 +- util/misc/uuid_test.cc | 9 +- util/net/http_transport_socket.cc | 5 +- util/net/http_transport_test.cc | 6 +- util/net/http_transport_test_server.cc | 6 +- util/numeric/checked_address_range.cc | 21 +- util/posix/close_multiple.cc | 17 +- util/posix/drop_privileges.cc | 4 +- util/posix/process_info.h | 16 +- util/posix/process_info_test.cc | 21 +- util/posix/scoped_mmap.cc | 4 +- util/posix/signals.cc | 20 +- util/posix/signals_test.cc | 31 +- util/posix/symbolic_constants_posix.cc | 10 +- util/posix/symbolic_constants_posix_test.cc | 51 ++- util/process/process_id.h | 12 +- util/process/process_memory.h | 4 +- util/process/process_memory_native.h | 16 +- util/process/process_memory_range_test.cc | 7 +- util/process/process_memory_sanitized_test.cc | 13 +- util/process/process_memory_test.cc | 33 +- util/stdlib/aligned_allocator.cc | 24 +- util/stdlib/aligned_allocator_test.cc | 6 +- util/stdlib/strnlen.cc | 4 +- util/stdlib/strnlen.h | 4 +- util/synchronization/semaphore.h | 12 +- util/synchronization/semaphore_posix.cc | 7 +- util/synchronization/semaphore_test.cc | 33 +- util/thread/thread.h | 16 +- util/thread/worker_thread_test.cc | 3 +- 143 files changed, 1024 insertions(+), 913 deletions(-) diff --git a/DEPS b/DEPS index 8f9617f404..27e9520b46 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'c2bc7a2a195eb8940215d0b81767f022aa5ecfdd', + '6e2f204b4ae135c40a6c4b3c3a01f48a86c5e886', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/client/annotation.h b/client/annotation.h index 8e7a3cbdc1..aa110bd670 100644 --- a/client/annotation.h +++ b/client/annotation.h @@ -28,7 +28,7 @@ #include "build/build_config.h" namespace crashpad { -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) namespace internal { class InProcessIntermediateDumpHandler; } // namespace internal @@ -106,7 +106,7 @@ class Annotation { // variables defined in a constexpr function, which is valid. Avoid them // and the also-problematic DCHECK until all the infrastructure is updated: // https://crbug.com/crashpad/201. -#if !defined(OS_WIN) || (defined(_MSC_VER) && _MSC_VER >= 1910) +#if !BUILDFLAG(IS_WIN) || (defined(_MSC_VER) && _MSC_VER >= 1910) const UnderlyingType start = static_cast(Type::kUserDefinedStart); const UnderlyingType user_type = start + value; @@ -173,7 +173,7 @@ class Annotation { protected: friend class AnnotationList; -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) friend class internal::InProcessIntermediateDumpHandler; #endif diff --git a/client/annotation_list.h b/client/annotation_list.h index 02389530c8..1c2141fe6a 100644 --- a/client/annotation_list.h +++ b/client/annotation_list.h @@ -19,7 +19,7 @@ #include "client/annotation.h" namespace crashpad { -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) namespace internal { class InProcessIntermediateDumpHandler; } // namespace internal @@ -87,7 +87,7 @@ class AnnotationList { Iterator end(); protected: -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) friend class internal::InProcessIntermediateDumpHandler; #endif diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index 5c8156e01e..7a3732b8d8 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -68,7 +68,7 @@ bool CrashReportDatabase::NewReport::Initialize( return false; } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::wstring uuid_string = uuid_.ToWString(); #else const std::string uuid_string = uuid_.ToString(); @@ -103,7 +103,7 @@ FileWriter* CrashReportDatabase::NewReport::AddAttachment( report_attachments_dir, FilePermissions::kOwnerOnly, true)) { return nullptr; } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::wstring name_string = base::UTF8ToWide(name); #else const std::string name_string = name; @@ -137,7 +137,7 @@ void CrashReportDatabase::UploadReport::InitializeAttachments() { continue; } attachment_readers_.emplace_back(std::move(file_reader)); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::string name_string = base::WideToUTF8(filename.value()); #else const std::string name_string = filename.value(); @@ -177,7 +177,7 @@ CrashReportDatabase::OperationStatus CrashReportDatabase::RecordUploadComplete( } base::FilePath CrashReportDatabase::AttachmentsPath(const UUID& uuid) { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::wstring uuid_string = uuid.ToWString(); #else const std::string uuid_string = uuid.ToString(); diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index 754f578c0b..9d48b68be5 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -600,7 +600,7 @@ base::FilePath CrashReportDatabaseGeneric::ReportPath(const UUID& uuid, DCHECK_NE(state, kUninitialized); DCHECK_NE(state, kSearchable); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::wstring uuid_string = uuid.ToWString(); #else const std::string uuid_string = uuid.ToString(); diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index 357702b069..d75ab355b9 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -737,7 +737,7 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { ASSERT_TRUE(LoggingRemoveFile(report.file_path)); -#if !defined(OS_APPLE) && !defined(OS_WIN) +#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) // CrashReportDatabaseMac stores metadata in xattrs and does not have .meta // files. // CrashReportDatabaseWin stores metadata in a global metadata file and not @@ -749,7 +749,7 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { ASSERT_EQ(db()->LookUpCrashReport(uuid, &report), CrashReportDatabase::kReportNotFound); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) const std::wstring uuid_string = uuid.ToWString(); #else const std::string uuid_string = uuid.ToString(); @@ -763,7 +763,7 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { EXPECT_TRUE(FileExists(file_path1)); EXPECT_TRUE(FileExists(file_path1)); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // On Windows, reports removed from metadata are counted, even if the file // is not on the disk. EXPECT_EQ(db()->CleanDatabase(0), 1); @@ -778,7 +778,7 @@ TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { // This test uses knowledge of the database format to break it, so it only // applies to the unfified database implementation. -#if !defined(OS_APPLE) && !defined(OS_WIN) +#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) TEST_F(CrashReportDatabaseTest, CleanBrokenDatabase) { // Remove report files if metadata goes missing. CrashReportDatabase::Report report; @@ -843,7 +843,7 @@ TEST_F(CrashReportDatabaseTest, CleanBrokenDatabase) { EXPECT_FALSE(PathExists(report.file_path)); EXPECT_FALSE(PathExists(metadata3)); } -#endif // !OS_APPLE && !OS_WIN +#endif // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) TEST_F(CrashReportDatabaseTest, TotalSize_MainReportOnly) { std::unique_ptr new_report; diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 468c83617a..a5e54a581f 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -28,12 +28,12 @@ #include "util/file/file_io.h" #include "util/misc/capture_context.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "base/mac/scoped_mach_port.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include "util/win/scoped_handle.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include #include #endif @@ -125,7 +125,8 @@ class CrashpadClient { bool asynchronous_start, const std::vector& attachments = {}); -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || DOXYGEN +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + DOXYGEN //! \brief Retrieve the socket and process ID for the handler. //! //! `StartHandler()` must have successfully been called before calling this @@ -170,9 +171,10 @@ class CrashpadClient { //! //! \return `true` on success. Otherwise `false` with a message logged. static bool InitializeSignalStackForThread(); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS || DOXYGEN +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) || DOXYGEN -#if defined(OS_ANDROID) || DOXYGEN +#if BUILDFLAG(IS_ANDROID) || DOXYGEN //! \brief Installs a signal handler to execute `/system/bin/app_process` and //! load a Java class in response to a crash. //! @@ -339,9 +341,10 @@ class CrashpadClient { const std::map& annotations, const std::vector& arguments, int socket); -#endif // OS_ANDROID || DOXYGEN +#endif // BUILDFLAG(IS_ANDROID) || DOXYGEN -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) || DOXYGEN +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || \ + DOXYGEN //! \brief Installs a signal handler to launch a handler process in reponse to //! a crash. //! @@ -454,9 +457,10 @@ class CrashpadClient { //! //! \param[in] unhandled_signals The set of unhandled signals void SetUnhandledSignals(const std::set& unhandled_signals); -#endif // OS_LINUX || OS_ANDROID || OS_CHROMEOS || DOXYGEN +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || + // BUILDFLAG(IS_CHROMEOS) || DOXYGEN -#if defined(OS_IOS) || DOXYGEN +#if BUILDFLAG(IS_IOS) || DOXYGEN //! \brief Configures the process to direct its crashes to the iOS in-process //! Crashpad handler. //! @@ -556,7 +560,7 @@ class CrashpadClient { const base::FilePath path); #endif -#if defined(OS_APPLE) || DOXYGEN +#if BUILDFLAG(IS_APPLE) || DOXYGEN //! \brief Sets the process’ crash handler to a Mach service registered with //! the bootstrap server. //! @@ -606,7 +610,7 @@ class CrashpadClient { base::mac::ScopedMachSendRight GetHandlerMachPort() const; #endif -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief Sets the IPC pipe of a presumably-running Crashpad handler process //! which was started with StartHandler() or by other compatible means //! and does an IPC message exchange to register this process with the @@ -706,7 +710,7 @@ class CrashpadClient { }; #endif -#if defined(OS_APPLE) || DOXYGEN +#if BUILDFLAG(IS_APPLE) || DOXYGEN //! \brief Configures the process to direct its crashes to the default handler //! for the operating system. //! @@ -740,14 +744,14 @@ class CrashpadClient { #endif private: -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) base::mac::ScopedMachSendRight exception_port_; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) std::wstring ipc_pipe_; ScopedKernelHANDLE handler_start_thread_; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) std::set unhandled_signals_; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) }; } // namespace crashpad diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index eccf204ca1..4c9a307c54 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -28,6 +28,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "client/client_argv_handling.h" #include "third_party/lss/lss.h" @@ -56,7 +57,7 @@ std::string FormatArgumentAddress(const std::string& name, const void* addr) { return base::StringPrintf("--%s=%p", name.c_str(), addr); } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) std::vector BuildAppProcessArgs( const std::string& class_name, @@ -124,7 +125,7 @@ std::vector BuildArgsToLaunchWithLinker( return argv; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) // A base class for Crashpad signal handler implementations. class SignalHandler { @@ -415,7 +416,7 @@ bool CrashpadClient::StartHandler( std::move(client_sock), handler_pid, &unhandled_signals_); } -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // static bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) { auto signal_handler = RequestCrashDumpHandler::Get(); @@ -519,9 +520,10 @@ bool CrashpadClient::InitializeSignalStackForThread() { } return true; } -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) bool CrashpadClient::StartJavaHandlerAtCrash( const std::string& class_name, diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 1ab974e7f7..08c78b0b9c 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -23,6 +23,7 @@ #include "base/check_op.h" #include "base/notreached.h" +#include "build/build_config.h" #include "client/annotation.h" #include "client/annotation_list.h" #include "client/crash_report_database.h" @@ -50,7 +51,7 @@ #include "util/posix/signals.h" #include "util/thread/thread.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #include "dlfcn_internal.h" @@ -140,7 +141,7 @@ constexpr char kTestAnnotationValue[] = "value_of_annotation"; constexpr char kTestAttachmentName[] = "test_attachment"; constexpr char kTestAttachmentContent[] = "attachment_content"; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) constexpr char kTestAbortMessage[] = "test abort message"; #endif @@ -179,7 +180,7 @@ void ValidateDump(const StartHandlerForSelfTestOptions& options, ProcessSnapshotMinidump minidump_snapshot; ASSERT_TRUE(minidump_snapshot.Initialize(report->Reader())); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // This part of the test requires Q. The API level on Q devices will be 28 // until the API is finalized, so we can't check API level yet. For now, test // for the presence of a libc symbol which was introduced in Q. @@ -363,7 +364,7 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) { return EXIT_FAILURE; } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) if (android_set_abort_message) { android_set_abort_message(kTestAbortMessage); } diff --git a/client/crashpad_info.cc b/client/crashpad_info.cc index 929c0df11f..8f13276fd8 100644 --- a/client/crashpad_info.cc +++ b/client/crashpad_info.cc @@ -16,10 +16,11 @@ #include +#include "build/build_config.h" #include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include #endif @@ -52,10 +53,10 @@ static_assert(std::is_standard_layout::value, // because it’s POD, no code should need to run to initialize this under // release-mode optimization. -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) __attribute__(( -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // Put the structure in a well-known section name where it can be easily // found without having to consult the symbol table. section(SEG_DATA ",crashpad_info"), @@ -77,16 +78,16 @@ __attribute__(( // The “used” attribute prevents the structure from being dead-stripped. used)) -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) // Put the struct in a section name CPADinfo where it can be found without the // symbol table. #pragma section("CPADinfo", read, write) __declspec(allocate("CPADinfo")) -#else // !defined(OS_POSIX) && !defined(OS_WIN) +#else // !BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_WIN) #error Port -#endif // !defined(OS_POSIX) && !defined(OS_WIN) +#endif // !BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_WIN) CrashpadInfo g_crashpad_info; @@ -94,8 +95,8 @@ extern "C" int* CRASHPAD_NOTE_REFERENCE; // static CrashpadInfo* CrashpadInfo::GetCrashpadInfo() { -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \ - defined(OS_FUCHSIA) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \ + BUILDFLAG(IS_FUCHSIA) // This otherwise-unused reference is used so that any module that // references GetCrashpadInfo() will also include the note in the // .note.crashpad.info section. That note in turn contains the address of diff --git a/client/crashpad_info.h b/client/crashpad_info.h index cc05398e3f..6c7ce3277e 100644 --- a/client/crashpad_info.h +++ b/client/crashpad_info.h @@ -23,15 +23,15 @@ #include "client/simple_string_dictionary.h" #include "util/misc/tri_state.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) namespace crashpad { namespace internal { -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) class InProcessIntermediateDumpHandler; #endif @@ -230,7 +230,7 @@ struct CrashpadInfo { }; protected: -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) friend class internal::InProcessIntermediateDumpHandler; #endif diff --git a/client/settings.cc b/client/settings.cc index 3855b9b6a4..966481d628 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -20,12 +20,13 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "build/build_config.h" #include "util/file/filesystem.h" #include "util/numeric/in_range_cast.h" namespace crashpad { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) Settings::ScopedLockedFileHandle::ScopedLockedFileHandle() : handle_(kInvalidFileHandle), lockfile_path_() { @@ -68,7 +69,7 @@ void Settings::ScopedLockedFileHandle::Destroy() { } } -#else // OS_FUCHSIA +#else // BUILDFLAG(IS_FUCHSIA) namespace internal { @@ -82,7 +83,7 @@ void ScopedLockedFileHandleTraits::Free(FileHandle handle) { } // namespace internal -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) struct Settings::Data { static constexpr uint32_t kSettingsMagic = 'CPds'; @@ -193,7 +194,7 @@ Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle( FileLocking locking, const base::FilePath& file_path) { ScopedFileHandle scoped(file); -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) base::FilePath lockfile_path(file_path.value() + ".__lock__"); if (scoped.is_valid()) { ScopedFileHandle lockfile_scoped( diff --git a/client/settings.h b/client/settings.h index d17f357ed4..82f893a055 100644 --- a/client/settings.h +++ b/client/settings.h @@ -125,7 +125,7 @@ class Settings { // and closes the file on destruction. Note that on Fuchsia, this handle DOES // NOT offer correct operation, only an attempt to DCHECK if racy behavior is // detected. -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) struct ScopedLockedFileHandle { public: ScopedLockedFileHandle(); @@ -155,10 +155,10 @@ class Settings { FileHandle handle_; base::FilePath lockfile_path_; }; -#else // OS_FUCHSIA +#else // BUILDFLAG(IS_FUCHSIA) using ScopedLockedFileHandle = base::ScopedGeneric; -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) static ScopedLockedFileHandle MakeScopedLockedFileHandle( FileHandle file, FileLocking locking, diff --git a/client/settings_test.cc b/client/settings_test.cc index 5f13cfcca8..74a2014718 100644 --- a/client/settings_test.cc +++ b/client/settings_test.cc @@ -154,7 +154,7 @@ TEST_F(SettingsTest, UnlinkFile) { EXPECT_TRUE(settings()->SetUploadsEnabled(true)); EXPECT_TRUE(settings()->SetLastUploadAttemptTime(time(nullptr))); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) EXPECT_EQ(_wunlink(settings_path().value().c_str()), 0) << ErrnoMessage("_wunlink"); #else diff --git a/client/simulate_crash.h b/client/simulate_crash.h index d01e1682d7..62a2ff9384 100644 --- a/client/simulate_crash.h +++ b/client/simulate_crash.h @@ -17,13 +17,13 @@ #include "build/build_config.h" -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) #include "client/simulate_crash_mac.h" -#elif defined(OS_IOS) +#elif BUILDFLAG(IS_IOS) #include "client/simulate_crash_ios.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include "client/simulate_crash_win.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "client/simulate_crash_linux.h" #endif diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index 3872e1142f..c691361494 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -40,9 +40,9 @@ #include "util/net/url.h" #include "util/stdlib/map_insert.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "handler/mac/file_limit_annotation.h" -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { @@ -51,7 +51,7 @@ namespace { // The number of seconds to wait between checking for pending reports. const int kRetryWorkIntervalSeconds = 15 * 60; -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // The number of times to attempt to upload a pending report, repeated on // failure. Attempts will happen once per launch, once per call to // ReportPending(), and, if Options.watch_pending_reports is true, once every @@ -152,9 +152,9 @@ void CrashReportUploadThread::ProcessPendingReports() { void CrashReportUploadThread::ProcessPendingReport( const CrashReportDatabase::Report& report) { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) RecordFileLimitAnnotation(); -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) Settings* const settings = database_->GetSettings(); @@ -172,7 +172,7 @@ void CrashReportUploadThread::ProcessPendingReport( if (ShouldRateLimitUpload(report)) return; -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) if (ShouldRateLimitRetry(report)) return; #endif @@ -217,7 +217,7 @@ void CrashReportUploadThread::ProcessPendingReport( report.uuid, Metrics::CrashSkippedReason::kPrepareForUploadFailed); break; case UploadResult::kRetry: -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) if (upload_report->upload_attempts > kRetryAttempts) { upload_report.reset(); database_->SkipReportUpload(report.uuid, @@ -377,7 +377,7 @@ bool CrashReportUploadThread::ShouldRateLimitUpload( return false; } -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) bool CrashReportUploadThread::ShouldRateLimitRetry( const CrashReportDatabase::Report& report) { if (retry_uuid_time_map_.find(report.uuid) != retry_uuid_time_map_.end()) { diff --git a/handler/crash_report_upload_thread.h b/handler/crash_report_upload_thread.h index 7649ae0db4..70f1628354 100644 --- a/handler/crash_report_upload_thread.h +++ b/handler/crash_report_upload_thread.h @@ -19,6 +19,7 @@ #include #include +#include "build/build_config.h" #include "client/crash_report_database.h" #include "util/misc/uuid.h" #include "util/stdlib/thread_safe_vector.h" @@ -186,7 +187,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate, //! upload attempts to be retried. bool ShouldRateLimitUpload(const CrashReportDatabase::Report& report); -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) //! \brief Rate-limit report retries. //! //! \param[in] report The crash report to process. @@ -206,7 +207,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate, const std::string url_; WorkerThread thread_; ThreadSafeVector known_pending_report_uuids_; -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // This is not thread-safe, and only used by the worker thread. std::map retry_uuid_time_map_; #endif diff --git a/handler/crashpad_handler_test_extended_handler.cc b/handler/crashpad_handler_test_extended_handler.cc index 4abcacd50f..9901aba2af 100644 --- a/handler/crashpad_handler_test_extended_handler.cc +++ b/handler/crashpad_handler_test_extended_handler.cc @@ -19,7 +19,7 @@ #include "minidump/test/minidump_user_extension_stream_util.h" #include "tools/tool_support.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #endif @@ -55,16 +55,16 @@ int ExtendedHandlerMain(int argc, char* argv[]) { } // namespace -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return ExtendedHandlerMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, &ExtendedHandlerMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 5e8ff1a2d2..cb78aa1680 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -60,13 +60,13 @@ #include "handler/linux/cros_crash_report_exception_handler.h" #endif -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include #include "handler/linux/crash_report_exception_handler.h" #include "handler/linux/exception_handler_server.h" #include "util/posix/signals.h" -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) #include #include @@ -78,7 +78,7 @@ #include "util/mach/child_port_handshake.h" #include "util/posix/close_stdio.h" #include "util/posix/signals.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include "handler/win/crash_report_exception_handler.h" @@ -86,32 +86,42 @@ #include "util/win/handle.h" #include "util/win/initial_client_data.h" #include "util/win/session_end_watcher.h" -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { namespace { -#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ - defined(OS_ANDROID) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) #define ATTACHMENTS_SUPPORTED 1 -#endif // OS_WIN || OS_LINUX || OS_CHROMEOS || OS_ANDROID +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) void Usage(const base::FilePath& me) { + // clang-format off fprintf(stderr, "Usage: %" PRFilePath " [OPTION]...\n" "Crashpad's exception handler server.\n" "\n" " --annotation=KEY=VALUE set a process annotation in each crash report\n" + // clang-format on #if defined(ATTACHMENTS_SUPPORTED) + // clang-format off " --attachment=FILE_PATH attach specified file to each crash report\n" " at the time of the crash\n" + // clang-format on #endif // ATTACHMENTS_SUPPORTED + // clang-format off " --database=PATH store the crash report database at PATH\n" -#if defined(OS_APPLE) + // clang-format on +#if BUILDFLAG(IS_APPLE) + // clang-format off " --handshake-fd=FD establish communication with the client over FD\n" -#endif // OS_APPLE -#if defined(OS_WIN) + // clang-format on +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_WIN) + // clang-format off " --initial-client-data=HANDLE_request_crash_dump,\n" " HANDLE_request_non_crash_dump,\n" " HANDLE_non_crash_dump_completed,\n" @@ -121,13 +131,20 @@ 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_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) + // clang-format on +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + // clang-format off " --initial-client-fd=FD a socket connected to a client.\n" -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS -#if defined(OS_APPLE) + // clang-format on +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) +#if BUILDFLAG(IS_APPLE) + // clang-format off " --mach-service=SERVICE register SERVICE with the bootstrap server\n" -#endif // OS_APPLE + // clang-format on +#endif // BUILDFLAG(IS_APPLE) + // clang-format off " --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" @@ -140,18 +157,26 @@ void Usage(const base::FilePath& me) { " --no-periodic-tasks don't scan for new reports or prune the database\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_ANDROID) + // clang-format on +#if BUILDFLAG(IS_ANDROID) + // clang-format off " --no-write-minidump-to-database\n" " don't write minidump to database\n" -#endif // OS_ANDROID -#if defined(OS_WIN) + // clang-format on +#endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_WIN) + // clang-format off " --pipe-name=PIPE communicate with the client over PIPE\n" -#endif // OS_WIN -#if defined(OS_APPLE) + // clang-format on +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_APPLE) + // clang-format off " --reset-own-crash-exception-port-to-system-default\n" " reset the server's exception handler to default\n" -#endif // OS_APPLE -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) + // clang-format on +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) + // clang-format off " --sanitization-information=SANITIZATION_INFORMATION_ADDRESS\n" " the address of a SanitizationInformation struct.\n" " --shared-client-connection the file descriptor provided by\n" @@ -159,10 +184,15 @@ void Usage(const base::FilePath& me) { " clients\n" " --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n" " request a dump for the handler's parent process\n" -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID + // clang-format on +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) + // clang-format off " --url=URL send crash reports to this Breakpad server URL,\n" " only if uploads are enabled for the database\n" + // clang-format on #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) + // clang-format off " --use-cros-crash-reporter\n" " pass crash reports to /sbin/crash_reporter\n" " instead of storing them in the database\n" @@ -173,13 +203,18 @@ void Usage(const base::FilePath& me) { " pass the --always_allow_feedback flag to\n" " crash_reporter, thus skipping metrics consent\n" " checks\n" + // clang-format on #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) + // clang-format off " --write-minidump-to-log write minidump to log\n" -#endif // OS_ANDROID + // clang-format on +#endif // BUILDFLAG(IS_ANDROID) + // clang-format off " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -190,23 +225,23 @@ struct Options { base::FilePath database; base::FilePath metrics_dir; std::vector monitor_self_arguments; -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) std::string mach_service; int handshake_fd; bool reset_own_crash_exception_port_to_system_default; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) VMAddress exception_information_address; VMAddress sanitization_information_address; int initial_client_fd; bool shared_client_connection; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) bool write_minidump_to_log; bool write_minidump_to_database; -#endif // OS_ANDROID -#elif defined(OS_WIN) +#endif // BUILDFLAG(IS_ANDROID) +#elif BUILDFLAG(IS_WIN) std::string pipe_name; InitialClientData initial_client_data; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) bool identify_client_via_url; bool monitor_self; bool periodic_tasks; @@ -278,8 +313,8 @@ class CallMetricsRecordNormalExit { } }; -#if defined(OS_APPLE) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ - defined(OS_ANDROID) +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); @@ -339,7 +374,7 @@ void InstallCrashHandler() { Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr); } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) struct ResetSIGTERMTraits { static struct sigaction* InvalidValue() { @@ -365,9 +400,9 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { g_exception_handler_server->Stop(); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; @@ -424,7 +459,7 @@ void InstallCrashHandler() { new TerminateHandler(); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) void MonitorSelf(const Options& options) { base::FilePath executable_path; @@ -460,7 +495,7 @@ 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_ANDROID) +#if BUILDFLAG(IS_ANDROID) if (!crashpad_client.StartHandlerAtCrash(executable_path, options.database, base::FilePath(), @@ -513,7 +548,7 @@ void InitCrashpadLogging() { #if BUILDFLAG(IS_CHROMEOS_ASH) settings.logging_dest = logging::LOG_TO_FILE; settings.log_file_path = "/var/log/chrome/chrome"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; #else settings.logging_dest = @@ -540,23 +575,24 @@ int HandlerMain(int argc, // Long options without short equivalents. kOptionLastChar = 255, kOptionAnnotation, -#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ - defined(OS_ANDROID) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) kOptionAttachment, -#endif // OS_WIN || OS_LINUX +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) kOptionDatabase, -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) kOptionHandshakeFD, -#endif // OS_APPLE -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_WIN) kOptionInitialClientData, -#endif // OS_WIN -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) kOptionInitialClientFD, -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS -#if defined(OS_APPLE) +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) +#if BUILDFLAG(IS_APPLE) kOptionMachService, -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) kOptionMetrics, kOptionMonitorSelf, kOptionMonitorSelfAnnotation, @@ -565,16 +601,16 @@ int HandlerMain(int argc, kOptionNoPeriodicTasks, kOptionNoRateLimit, kOptionNoUploadGzip, -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) kOptionNoWriteMinidumpToDatabase, -#endif // OS_ANDROID -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_WIN) kOptionPipeName, -#endif // OS_WIN -#if defined(OS_APPLE) +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_APPLE) kOptionResetOwnCrashExceptionPortToSystemDefault, -#endif // OS_APPLE -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) kOptionSanitizationInformation, kOptionSharedClientConnection, kOptionTraceParentWithException, @@ -585,9 +621,9 @@ int HandlerMain(int argc, kOptionMinidumpDirForTests, kOptionAlwaysAllowFeedback, #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) kOptionWriteMinidumpToLog, -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) // Standard options. kOptionHelp = -2, @@ -600,21 +636,22 @@ int HandlerMain(int argc, {"attachment", required_argument, nullptr, kOptionAttachment}, #endif // ATTACHMENTS_SUPPORTED {"database", required_argument, nullptr, kOptionDatabase}, -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, -#endif // OS_APPLE -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_WIN) {"initial-client-data", required_argument, nullptr, kOptionInitialClientData}, -#endif // OS_APPLE -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD}, -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS -#if defined(OS_APPLE) +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) +#if BUILDFLAG(IS_APPLE) {"mach-service", required_argument, nullptr, kOptionMachService}, -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) {"metrics-dir", required_argument, nullptr, kOptionMetrics}, {"monitor-self", no_argument, nullptr, kOptionMonitorSelf}, {"monitor-self-annotation", @@ -632,22 +669,22 @@ int HandlerMain(int argc, {"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks}, {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip}, -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) {"no-write-minidump-to-database", no_argument, nullptr, kOptionNoWriteMinidumpToDatabase}, -#endif // OS_ANDROID -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_WIN) {"pipe-name", required_argument, nullptr, kOptionPipeName}, -#endif // OS_WIN -#if defined(OS_APPLE) +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_APPLE) {"reset-own-crash-exception-port-to-system-default", no_argument, nullptr, kOptionResetOwnCrashExceptionPortToSystemDefault}, -#endif // OS_APPLE -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) {"sanitization-information", required_argument, nullptr, @@ -660,42 +697,40 @@ int HandlerMain(int argc, required_argument, nullptr, kOptionTraceParentWithException}, -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) {"url", required_argument, nullptr, kOptionURL}, #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) {"use-cros-crash-reporter", - no_argument, - nullptr, - kOptionUseCrosCrashReporter}, + no_argument, + nullptr, + kOptionUseCrosCrashReporter}, {"minidump-dir-for-tests", - required_argument, - nullptr, - kOptionMinidumpDirForTests}, - {"always-allow-feedback", - no_argument, - nullptr, - kOptionAlwaysAllowFeedback}, + required_argument, + nullptr, + kOptionMinidumpDirForTests}, + {"always-allow-feedback", no_argument, nullptr, kOptionAlwaysAllowFeedback}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) {"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog}, -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, {nullptr, 0, nullptr, 0}, }; Options options = {}; -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) options.handshake_fd = -1; #endif options.identify_client_via_url = true; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) options.initial_client_fd = kInvalidFileHandle; #endif options.periodic_tasks = true; options.rate_limit = true; options.upload_gzip = true; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) options.write_minidump_to_database = true; #endif @@ -720,7 +755,7 @@ int HandlerMain(int argc, ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); break; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) case kOptionHandshakeFD: { if (!StringToNumber(optarg, &options.handshake_fd) || options.handshake_fd < 0) { @@ -734,8 +769,8 @@ int HandlerMain(int argc, options.mach_service = optarg; break; } -#endif // OS_APPLE -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_WIN) case kOptionInitialClientData: { if (!options.initial_client_data.InitializeFromString(optarg)) { ToolSupport::UsageHint( @@ -744,8 +779,8 @@ int HandlerMain(int argc, } break; } -#endif // OS_WIN -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) case kOptionInitialClientFD: { if (!base::StringToInt(optarg, &options.initial_client_fd)) { ToolSupport::UsageHint(me, "failed to parse --initial-client-fd"); @@ -753,7 +788,8 @@ int HandlerMain(int argc, } break; } -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) case kOptionMetrics: { options.metrics_dir = base::FilePath( ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); @@ -791,25 +827,25 @@ int HandlerMain(int argc, options.upload_gzip = false; break; } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) case kOptionNoWriteMinidumpToDatabase: { options.write_minidump_to_database = false; break; } -#endif // OS_ANDROID -#if defined(OS_WIN) +#endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_WIN) case kOptionPipeName: { options.pipe_name = optarg; break; } -#endif // OS_WIN -#if defined(OS_APPLE) +#endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_APPLE) case kOptionResetOwnCrashExceptionPortToSystemDefault: { options.reset_own_crash_exception_port_to_system_default = true; break; } -#endif // OS_APPLE -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) case kOptionSanitizationInformation: { if (!StringToNumber(optarg, &options.sanitization_information_address)) { @@ -831,7 +867,8 @@ int HandlerMain(int argc, } break; } -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) case kOptionURL: { options.url = optarg; break; @@ -851,12 +888,12 @@ int HandlerMain(int argc, break; } #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) case kOptionWriteMinidumpToLog: { options.write_minidump_to_log = true; break; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) case kOptionHelp: { Usage(me); MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); @@ -876,7 +913,7 @@ int HandlerMain(int argc, argc -= optind; argv += optind; -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (options.handshake_fd < 0 && options.mach_service.empty()) { ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); return ExitFailure(); @@ -886,7 +923,7 @@ int HandlerMain(int argc, me, "--handshake-fd and --mach-service are incompatible"); return ExitFailure(); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { ToolSupport::UsageHint(me, "--initial-client-data or --pipe-name is required"); @@ -897,7 +934,7 @@ int HandlerMain(int argc, me, "--initial-client-data and --pipe-name are incompatible"); return ExitFailure(); } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) if (!options.exception_information_address && options.initial_client_fd == kInvalidFileHandle) { ToolSupport::UsageHint( @@ -917,15 +954,15 @@ int HandlerMain(int argc, me, "--shared-client-connection requires --initial-client-fd"); return ExitFailure(); } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) if (!options.write_minidump_to_log && !options.write_minidump_to_database) { ToolSupport::UsageHint(me, "--no_write_minidump_to_database is required to use " "with --write_minidump_to_log."); ExitFailure(); } -#endif // OS_ANDROID -#endif // OS_APPLE +#endif // BUILDFLAG(IS_ANDROID) +#endif // BUILDFLAG(IS_APPLE) if (options.database.empty()) { ToolSupport::UsageHint(me, "--database is required"); @@ -937,11 +974,11 @@ int HandlerMain(int argc, return ExitFailure(); } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (options.reset_own_crash_exception_port_to_system_default) { CrashpadClient::UseSystemDefaultHandler(); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) if (options.monitor_self) { MonitorSelf(options); @@ -990,7 +1027,7 @@ int HandlerMain(int argc, upload_thread.Get()->Start(); } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) std::unique_ptr exception_handler; #else std::unique_ptr exception_handler; @@ -1030,18 +1067,18 @@ int HandlerMain(int argc, #if defined(ATTACHMENTS_SUPPORTED) &options.attachments, #endif // ATTACHMENTS_SUPPORTED -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) options.write_minidump_to_database, options.write_minidump_to_log, -#endif // OS_ANDROID -#if defined(OS_LINUX) +#endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_LINUX) true, false, -#endif // OS_LINUX +#endif // BUILDFLAG(IS_LINUX) user_stream_sources); #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) if (options.exception_information_address) { ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = options.exception_information_address; @@ -1051,7 +1088,8 @@ int HandlerMain(int argc, ? EXIT_SUCCESS : ExitFailure(); } -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) ScopedStoppable prune_thread; if (options.periodic_tasks) { @@ -1060,7 +1098,7 @@ int HandlerMain(int argc, prune_thread.Get()->Start(); } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (options.mach_service.empty()) { // Don’t do this when being run by launchd. See launchd.plist(5). CloseStdinAndStdout(); @@ -1103,7 +1141,7 @@ int HandlerMain(int argc, } RecordFileLimitAnnotation(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) // Shut down as late as possible relative to programs we're watching. if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY)) PLOG(ERROR) << "SetProcessShutdownParameters"; @@ -1113,9 +1151,9 @@ int HandlerMain(int argc, if (!options.pipe_name.empty()) { exception_handler_server.SetPipeName(base::UTF8ToWide(options.pipe_name)); } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ExceptionHandlerServer exception_handler_server; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) base::GlobalHistogramAllocator* histogram_allocator = nullptr; if (!options.metrics_dir.empty()) { @@ -1130,19 +1168,19 @@ int HandlerMain(int argc, Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) if (options.initial_client_data.IsValid()) { exception_handler_server.InitializeWithInheritedDataForInitialClient( options.initial_client_data, exception_handler.get()); } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) if (options.initial_client_fd == kInvalidFileHandle || !exception_handler_server.InitializeWithClient( ScopedFileHandle(options.initial_client_fd), options.shared_client_connection)) { return ExitFailure(); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) exception_handler_server.Run(exception_handler.get()); diff --git a/handler/handler_main.h b/handler/handler_main.h index 252654118a..b6cc467cdd 100644 --- a/handler/handler_main.h +++ b/handler/handler_main.h @@ -35,7 +35,7 @@ int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) //! \brief The `main()` entry point for Android libraries. //! //! This symbol is the entry point for crashpad when it is dynamically loaded diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 84f9534fed..88378a9fa4 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -36,7 +36,7 @@ #include "util/stream/log_output_stream.h" #include "util/stream/zlib_output_stream.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -52,7 +52,7 @@ class Logger final : public LogOutputStream::Delegate { ~Logger() override = default; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) int Log(const char* buf) override { return __android_log_buf_write( LOG_ID_CRASH, ANDROID_LOG_FATAL, "crashpad", buf); diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 786bab1baa..c7fa90d894 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -30,7 +30,7 @@ #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif diff --git a/handler/main.cc b/handler/main.cc index 3ae73ecddf..855a5a7dee 100644 --- a/handler/main.cc +++ b/handler/main.cc @@ -17,17 +17,17 @@ #include "build/build_config.h" #include "tools/tool_support.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #endif -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return crashpad::HandlerMain(argc, argv, nullptr); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) namespace { @@ -50,4 +50,4 @@ int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, HandlerMainAdaptor); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index d7e53a4932..2f2d90ba47 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -21,6 +21,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" +#include "build/build_config.h" #include "snapshot/cpu_context.h" #include "util/file/file_writer.h" #include "util/stdlib/aligned_allocator.h" @@ -35,7 +36,7 @@ static_assert(sizeof(MinidumpContextAMD64) == 1232, "MinidumpContextAMD64 size"); // These structures can also be checked against definitions in the Windows SDK. -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #if defined(ARCH_CPU_X86_FAMILY) static_assert(sizeof(MinidumpContextX86) == sizeof(WOW64_CONTEXT), "WOW64_CONTEXT size"); @@ -45,7 +46,7 @@ static_assert(sizeof(MinidumpContextX86) == sizeof(CONTEXT), "CONTEXT size"); static_assert(sizeof(MinidumpContextAMD64) == sizeof(CONTEXT), "CONTEXT size"); #endif #endif // ARCH_CPU_X86_FAMILY -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index efeaeab4cb..e4be0b6dcb 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -418,12 +418,13 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) { // but the test should complete without failure. constexpr uint32_t kSnapshotTime = 0xfd469ab8; constexpr timeval kSnapshotTimeval = { -#ifdef OS_WIN - static_cast(kSnapshotTime), +#if BUILDFLAG(IS_WIN) + static_cast(kSnapshotTime), #else - static_cast(kSnapshotTime), + static_cast(kSnapshotTime), #endif - 0}; + 0 + }; TestProcessSnapshot process_snapshot; process_snapshot.SetSnapshotTime(kSnapshotTimeval); diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index 64c3c2371b..12c65b1a82 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -31,9 +31,9 @@ #include "util/numeric/in_range_cast.h" #include "util/numeric/safe_assignment.h" -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) #include -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) #include #endif @@ -67,7 +67,7 @@ std::string BuildString(const SystemSnapshot* system_snapshot) { return machine_description; } -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) // Converts the value of the __MAC_OS_X_VERSION_MIN_REQUIRED or // __MAC_OS_X_VERSION_MAX_ALLOWED macro from to a number // identifying the macOS version that it represents, in the same format used by @@ -93,7 +93,7 @@ int AvailabilityVersionToMacOSVersionNumber(int availability) { return availability; } -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) } // namespace @@ -107,17 +107,17 @@ std::string MinidumpMiscInfoDebugBuildString() { // Caution: the minidump file format only has room for 39 UTF-16 code units // plus a UTF-16 NUL terminator. Don’t let strings get longer than this, or // they will be truncated and a message will be logged. -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) static constexpr char kOS[] = "mac"; -#elif defined(OS_IOS) +#elif BUILDFLAG(IS_IOS) static constexpr char kOS[] = "ios"; -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) static constexpr char kOS[] = "android"; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) static constexpr char kOS[] = "linux"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) static constexpr char kOS[] = "win"; -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) static constexpr char kOS[] = "fuchsia"; #else #error define kOS for this operating system @@ -145,12 +145,12 @@ std::string MinidumpMiscInfoDebugBuildString() { PACKAGE_VERSION, kOS); -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) debug_build_string += base::StringPrintf( ",%d,%d", AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MIN_REQUIRED), AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MAX_ALLOWED)); -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) debug_build_string += base::StringPrintf(",%d", __ANDROID_API__); #endif diff --git a/snapshot/crashpad_info_client_options_test.cc b/snapshot/crashpad_info_client_options_test.cc index 4476e216ca..73df677b53 100644 --- a/snapshot/crashpad_info_client_options_test.cc +++ b/snapshot/crashpad_info_client_options_test.cc @@ -24,13 +24,13 @@ #include "test/scoped_module_handle.h" #include "test/test_paths.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include #include "snapshot/mac/process_snapshot_mac.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include "snapshot/win/process_snapshot_win.h" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #endif @@ -79,19 +79,19 @@ class ScopedUnsetCrashpadInfoOptions { }; CrashpadInfoClientOptions SelfProcessSnapshotAndGetCrashpadOptions() { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) ProcessSnapshotMac process_snapshot; EXPECT_TRUE(process_snapshot.Initialize(mach_task_self())); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ProcessSnapshotWin process_snapshot; EXPECT_TRUE(process_snapshot.Initialize( GetCurrentProcess(), ProcessSuspensionState::kRunning, 0, 0)); -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) ProcessSnapshotFuchsia process_snapshot; EXPECT_TRUE(process_snapshot.Initialize(*zx::process::self())); #else #error Port. -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) CrashpadInfoClientOptions options; process_snapshot.GetCrashpadOptions(&options); @@ -154,19 +154,19 @@ TEST(CrashpadInfoClientOptions, TwoModules) { TestPaths::BuildArtifact(FILE_PATH_LITERAL("snapshot"), FILE_PATH_LITERAL("module"), TestPaths::FileType::kLoadableModule); -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) ScopedModuleHandle module( dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL)); ASSERT_TRUE(module.valid()) << "dlopen " << module_path.value() << ": " << dlerror(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ScopedModuleHandle module(LoadLibrary(module_path.value().c_str())); ASSERT_TRUE(module.valid()) << "LoadLibrary " << base::WideToUTF8(module_path.value()) << ": " << ErrorMessage(); #else #error Port. -#endif // OS_APPLE +#endif // BUILDFLAG(IS_POSIX) // Get the function pointer from the module. This wraps GetCrashpadInfo(), but // because it runs in the module, it returns the remote module’s CrashpadInfo @@ -252,19 +252,19 @@ TEST_P(CrashpadInfoSizes_ClientOptions, DifferentlySizedStruct) { TestPaths::BuildArtifact(FILE_PATH_LITERAL("snapshot"), artifact, TestPaths::FileType::kLoadableModule); -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) ScopedModuleHandle module( dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL)); ASSERT_TRUE(module.valid()) << "dlopen " << module_path.value() << ": " << dlerror(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ScopedModuleHandle module(LoadLibrary(module_path.value().c_str())); ASSERT_TRUE(module.valid()) << "LoadLibrary " << base::WideToUTF8(module_path.value()) << ": " << ErrorMessage(); #else #error Port. -#endif // OS_APPLE +#endif // BUILDFLAG(IS_POSIX) // Get the function pointer from the module. CrashpadInfo* (*TestModule_GetCrashpadInfo)() = diff --git a/snapshot/crashpad_info_client_options_test_module.cc b/snapshot/crashpad_info_client_options_test_module.cc index 357d35e659..48795e3c80 100644 --- a/snapshot/crashpad_info_client_options_test_module.cc +++ b/snapshot/crashpad_info_client_options_test_module.cc @@ -15,12 +15,12 @@ #include "build/build_config.h" #include "client/crashpad_info.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #define EXPORT __attribute__((visibility("default"))) -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #define EXPORT __declspec(dllexport) -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) extern "C" { @@ -40,8 +40,8 @@ EXPORT crashpad::CrashpadInfo* TestModule_GetCrashpadInfo() { } // extern "C" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) { return TRUE; } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) diff --git a/snapshot/crashpad_info_size_test_module.cc b/snapshot/crashpad_info_size_test_module.cc index 584f83b0b7..0a9186c249 100644 --- a/snapshot/crashpad_info_size_test_module.cc +++ b/snapshot/crashpad_info_size_test_module.cc @@ -16,11 +16,11 @@ #include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { @@ -65,9 +65,9 @@ struct TestCrashpadInfo { // to get this test version to be interpreted as a genuine CrashpadInfo // structure. The size is set to the actual size of this structure (that’s kind // of the point of this test). -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) __attribute__(( -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) section(SEG_DATA ",crashpad_info"), #endif #if defined(ADDRESS_SANITIZER) @@ -75,12 +75,12 @@ __attribute__(( #endif // defined(ADDRESS_SANITIZER) visibility("hidden"), used)) -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #pragma section("CPADinfo", read, write) __declspec(allocate("CPADinfo")) -#else // !defined(OS_POSIX) && !defined(OS_WIN) +#else // !BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_WIN) #error Port -#endif // !defined(OS_POSIX) && !defined(OS_WIN) +#endif // !BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_WIN) TestCrashpadInfo g_test_crashpad_info = {'CPad', sizeof(TestCrashpadInfo), 1, @@ -105,14 +105,15 @@ TestCrashpadInfo g_test_crashpad_info = {'CPad', extern "C" { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) __attribute__((visibility("default"))) -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) __declspec(dllexport) #else #error Port -#endif // OS_POSIX -crashpad::TestCrashpadInfo* TestModule_GetCrashpadInfo() { +#endif // BUILDFLAG(IS_POSIX) +crashpad::TestCrashpadInfo* +TestModule_GetCrashpadInfo() { // Note that there's no need to do the back-reference here to the note on // POSIX like CrashpadInfo::GetCrashpadInfo() because the note .S file is // directly included into this test binary. @@ -121,8 +122,8 @@ crashpad::TestCrashpadInfo* TestModule_GetCrashpadInfo() { } // extern "C" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved) { return TRUE; } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) diff --git a/snapshot/crashpad_types/crashpad_info_reader.cc b/snapshot/crashpad_types/crashpad_info_reader.cc index cedab59a72..ad75292bd7 100644 --- a/snapshot/crashpad_types/crashpad_info_reader.cc +++ b/snapshot/crashpad_types/crashpad_info_reader.cc @@ -20,11 +20,11 @@ #include "client/crashpad_info.h" #include "util/misc/as_underlying_type.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include "util/win/traits.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/linux/traits.h" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include "util/fuchsia/traits.h" #endif diff --git a/snapshot/crashpad_types/crashpad_info_reader_test.cc b/snapshot/crashpad_types/crashpad_info_reader_test.cc index 3a1806a383..9c6e3c3723 100644 --- a/snapshot/crashpad_types/crashpad_info_reader_test.cc +++ b/snapshot/crashpad_types/crashpad_info_reader_test.cc @@ -30,7 +30,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #endif @@ -109,7 +109,7 @@ void ExpectCrashpadInfo(ProcessType process, VMAddress extra_memory_address, VMAddress simple_annotations_address, VMAddress annotations_list_address) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); diff --git a/snapshot/crashpad_types/image_annotation_reader_test.cc b/snapshot/crashpad_types/image_annotation_reader_test.cc index b5289e7a7f..f7f18cbd69 100644 --- a/snapshot/crashpad_types/image_annotation_reader_test.cc +++ b/snapshot/crashpad_types/image_annotation_reader_test.cc @@ -32,7 +32,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #endif @@ -94,7 +94,7 @@ void ExpectAnnotations(ProcessType process, bool is_64_bit, VMAddress simple_map_address, VMAddress annotation_list_address) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index 5ea14c0fe3..0b7d0145f2 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -733,13 +733,13 @@ bool ElfImageReader::GetAddressFromDynamicArray(uint64_t tag, if (!dynamic_array_->GetValue(tag, log, address)) { return false; } -#if defined(OS_ANDROID) || defined(OS_FUCHSIA) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) // The GNU loader updates the dynamic array according to the load bias. // The Android and Fuchsia loaders only update the debug address. if (tag != DT_DEBUG) { *address += GetLoadBias(); } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) return true; } diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 2ea55ad10b..161eab0292 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -30,12 +30,12 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) #include #include "base/fuchsia/fuchsia_logging.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "test/linux/fake_ptrace_connection.h" #include "util/linux/auxiliary_vector.h" @@ -45,7 +45,7 @@ #error Port. -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) extern "C" { __attribute__((visibility("default"))) void ElfImageReaderTestExportedSymbol() { @@ -56,8 +56,7 @@ namespace crashpad { namespace test { namespace { - -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) void LocateExecutable(const ProcessType& process, ProcessMemory* memory, @@ -84,7 +83,7 @@ void LocateExecutable(const ProcessType& process, *elf_address = base; } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) void LocateExecutable(PtraceConnection* connection, ProcessMemory* memory, @@ -104,7 +103,7 @@ void LocateExecutable(PtraceConnection* connection, *elf_address = possible_mappings->Next()->range.Base(); } -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) void ExpectSymbol(ElfImageReader* reader, const std::string& symbol_name, @@ -128,12 +127,12 @@ void ReadThisExecutableInTarget(ProcessType process, #endif // ARCH_CPU_64_BITS VMAddress elf_address; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); LocateExecutable(&connection, &memory, &elf_address); -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) ProcessMemoryFuchsia memory; ASSERT_TRUE(memory.Initialize(process)); LocateExecutable(process, &memory, &elf_address); @@ -192,7 +191,7 @@ void ReadLibcInTarget(ProcessType process, constexpr bool am_64_bit = false; #endif // ARCH_CPU_64_BITS -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); @@ -301,7 +300,7 @@ TEST(ElfImageReader, OneModuleChild) { test.Run(); } -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // crashpad_snapshot_test_both_dt_hash_styles is specially built and forced to // include both .hash and .gnu.hash sections. Linux, Android, and Fuchsia have @@ -356,7 +355,7 @@ TEST(ElfImageReader, DtHashAndDtGnuHashMatch) { EXPECT_EQ(from_dt_hash, from_dt_gnu_hash); } -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) } // namespace } // namespace test diff --git a/snapshot/linux/debug_rendezvous.cc b/snapshot/linux/debug_rendezvous.cc index 42384f7433..e0af2b3b18 100644 --- a/snapshot/linux/debug_rendezvous.cc +++ b/snapshot/linux/debug_rendezvous.cc @@ -21,7 +21,7 @@ #include "base/logging.h" #include "build/build_config.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -142,7 +142,7 @@ bool DebugRendezvous::InitializeSpecific(const ProcessMemoryRange& memory, modules_.push_back(entry); } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // Android P (API 28) mistakenly places the vdso in the first entry in the // link map. const int android_runtime_api = android_get_device_api_level(); @@ -151,7 +151,7 @@ bool DebugRendezvous::InitializeSpecific(const ProcessMemoryRange& memory, modules_[0] = executable_; executable_ = executable; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) return true; } diff --git a/snapshot/linux/debug_rendezvous_test.cc b/snapshot/linux/debug_rendezvous_test.cc index 4754528e85..9fa6d63114 100644 --- a/snapshot/linux/debug_rendezvous_test.cc +++ b/snapshot/linux/debug_rendezvous_test.cc @@ -41,7 +41,7 @@ #include "util/process/process_memory_linux.h" #include "util/process/process_memory_range.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -103,7 +103,7 @@ void TestAgainstTarget(PtraceConnection* connection) { DebugRendezvous debug; ASSERT_TRUE(debug.Initialize(range, debug_address)); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) const int android_runtime_api = android_get_device_api_level(); ASSERT_GE(android_runtime_api, 1); @@ -125,7 +125,7 @@ void TestAgainstTarget(PtraceConnection* connection) { // glibc's loader does not set the name for the executable. EXPECT_TRUE(debug.Executable()->name.empty()); EXPECT_EQ(debug.Executable()->dynamic_array, exe_dynamic_address); -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) // Android's loader doesn't set the load bias until Android 4.3 (API 18). if (android_runtime_api >= 18) { @@ -162,7 +162,7 @@ void TestAgainstTarget(PtraceConnection* connection) { ASSERT_GE(possible_mappings->Count(), 1u); std::unique_ptr module_reader; -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) const MemoryMap::Mapping* module_mapping = nullptr; #endif const MemoryMap::Mapping* mapping = nullptr; @@ -174,7 +174,7 @@ void TestAgainstTarget(PtraceConnection* connection) { parsed_module->GetDynamicArrayAddress(&dynamic_address) && dynamic_address == module.dynamic_array) { module_reader = std::move(parsed_module); -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) module_mapping = mapping; #endif break; @@ -182,7 +182,7 @@ void TestAgainstTarget(PtraceConnection* connection) { } ASSERT_TRUE(module_reader.get()); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_FALSE(module.name.empty()); #else // glibc's loader doesn't always set the name in the link map for the vdso. @@ -206,7 +206,7 @@ void TestAgainstTarget(PtraceConnection* connection) { module_mapping->device, module_mapping->inode, module.name); -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) // Android's loader stops setting its own load bias after Android 4.4.4 // (API 20) until Android 6.0 (API 23). diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index a9098ac803..5711f343a4 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -29,7 +29,7 @@ #include "util/linux/auxiliary_vector.h" #include "util/linux/proc_stat_reader.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -282,7 +282,7 @@ const std::vector& ProcessReaderLinux::Modules() { } void ProcessReaderLinux::InitializeAbortMessage() { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) const MemoryMap::Mapping* mapping = memory_map_.FindMappingWithName("[anon:abort message]"); if (!mapping) { @@ -297,7 +297,7 @@ void ProcessReaderLinux::InitializeAbortMessage() { #endif } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // These structure definitions and the magic numbers below were copied from // bionic/libc/bionic/android_set_abort_message.cpp @@ -346,7 +346,7 @@ void ProcessReaderLinux::ReadAbortMessage(const MemoryMap::Mapping* mapping) { } } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) const std::string& ProcessReaderLinux::AbortMessage() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); @@ -486,7 +486,7 @@ void ProcessReaderLinux::InitializeModules() { continue; } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // Beginning at API 21, Bionic provides android_dlopen_ext() which allows // passing a file descriptor with an existing relro segment to the loader. // This means that the mapping attributes of dyn_mapping may be unrelated diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index f3791f85ba..8cc90a0e88 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -53,7 +53,7 @@ #include "util/misc/memory_sanitizer.h" #include "util/synchronization/semaphore.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #include #include "dlfcn_internal.h" @@ -492,7 +492,7 @@ TEST(ProcessReaderLinux, MAYBE_ChildWithSplitStack) { } // Android doesn't provide dl_iterate_phdr on ARM until API 21. -#if !defined(OS_ANDROID) || !defined(ARCH_CPU_ARMEL) || __ANDROID_API__ >= 21 +#if !BUILDFLAG(IS_ANDROID) || !defined(ARCH_CPU_ARMEL) || __ANDROID_API__ >= 21 int ExpectFindModule(dl_phdr_info* info, size_t size, void* data) { SCOPED_TRACE( base::StringPrintf("module %s at 0x%" PRIx64 " phdrs 0x%" PRIx64, @@ -502,8 +502,7 @@ int ExpectFindModule(dl_phdr_info* info, size_t size, void* data) { auto modules = reinterpret_cast*>(data); - -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // Prior to API 27, Bionic includes a null entry for /system/bin/linker. if (!info->dlpi_name) { EXPECT_EQ(info->dlpi_addr, 0u); @@ -532,7 +531,7 @@ int ExpectFindModule(dl_phdr_info* info, size_t size, void* data) { EXPECT_TRUE(found); return 0; } -#endif // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 +#endif // !BUILDFLAG(IS_ANDROID) || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 void ExpectModulesFromSelf( const std::vector& modules) { @@ -542,14 +541,14 @@ void ExpectModulesFromSelf( } // Android doesn't provide dl_iterate_phdr on ARM until API 21. -#if !defined(OS_ANDROID) || !defined(ARCH_CPU_ARMEL) || __ANDROID_API__ >= 21 +#if !BUILDFLAG(IS_ANDROID) || !defined(ARCH_CPU_ARMEL) || __ANDROID_API__ >= 21 EXPECT_EQ( dl_iterate_phdr( ExpectFindModule, reinterpret_cast( const_cast*>(&modules))), 0); -#endif // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 +#endif // !BUILDFLAG(IS_ANDROID) || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 } #if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) @@ -641,7 +640,7 @@ TEST(ProcessReaderLinux, ChildModules) { test.Run(); } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) const char kTestAbortMessage[] = "test abort message"; TEST(ProcessReaderLinux, AbortMessage) { diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index a730b29eb5..b4be3de7b4 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -17,6 +17,7 @@ #include #include "base/logging.h" +#include "build/build_config.h" #include "util/linux/exception_information.h" namespace crashpad { @@ -306,7 +307,7 @@ void ProcessSnapshotLinux::InitializeModules() { } void ProcessSnapshotLinux::InitializeAnnotations() { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) const std::string& abort_message = process_reader_.AbortMessage(); if (!abort_message.empty()) { annotations_simple_map_["abort_message"] = abort_message; diff --git a/snapshot/linux/signal_context.h b/snapshot/linux/signal_context.h index 110024680b..c004f8f6df 100644 --- a/snapshot/linux/signal_context.h +++ b/snapshot/linux/signal_context.h @@ -119,11 +119,11 @@ template struct Sigset< Traits, typename std::enable_if::value>::type> { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) uint64_t val; #else typename Traits::ULong val[16]; -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) }; #if defined(ARCH_CPU_X86_FAMILY) diff --git a/snapshot/linux/system_snapshot_linux.cc b/snapshot/linux/system_snapshot_linux.cc index a99da3e4b6..e77bcafa9c 100644 --- a/snapshot/linux/system_snapshot_linux.cc +++ b/snapshot/linux/system_snapshot_linux.cc @@ -26,13 +26,14 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/posix/timezone.h" #include "util/file/file_io.h" #include "util/numeric/in_range_cast.h" #include "util/string/split_string.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -118,7 +119,7 @@ bool ReadFreqFile(const std::string& filename, uint64_t* hz) { return true; } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) bool ReadProperty(const char* property, std::string* value) { char value_buffer[PROP_VALUE_MAX]; int length = __system_property_get(property, value_buffer); @@ -129,7 +130,7 @@ bool ReadProperty(const char* property, std::string* value) { *value = value_buffer; return true; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) } // namespace @@ -158,13 +159,13 @@ void SystemSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, process_reader_ = process_reader; snapshot_time_ = snapshot_time; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) std::string build_string; if (ReadProperty("ro.build.fingerprint", &build_string)) { os_version_build_ = build_string; os_version_full_ = build_string; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) utsname uts; if (uname(&uts) != 0) { @@ -314,11 +315,11 @@ bool SystemSnapshotLinux::CPUX86SupportsDAZ() const { SystemSnapshot::OperatingSystem SystemSnapshotLinux::GetOperatingSystem() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) return kOperatingSystemAndroid; #else return kOperatingSystemLinux; -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) } bool SystemSnapshotLinux::OSServer() const { @@ -344,7 +345,7 @@ std::string SystemSnapshotLinux::OSVersionFull() const { std::string SystemSnapshotLinux::MachineDescription() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) std::string description; std::string prop; if (ReadProperty("ro.product.model", &prop)) { @@ -359,7 +360,7 @@ std::string SystemSnapshotLinux::MachineDescription() const { return description; #else return std::string(); -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) } bool SystemSnapshotLinux::NXEnabled() const { diff --git a/snapshot/linux/system_snapshot_linux_test.cc b/snapshot/linux/system_snapshot_linux_test.cc index f5d26a1e74..09c219602a 100644 --- a/snapshot/linux/system_snapshot_linux_test.cc +++ b/snapshot/linux/system_snapshot_linux_test.cc @@ -65,11 +65,11 @@ TEST(SystemSnapshotLinux, Basic) { system.CPURevision(); system.NXEnabled(); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_FALSE(system.MachineDescription().empty()); #else system.MachineDescription(); -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) #if defined(ARCH_CPU_X86_FAMILY) system.CPUX86Signature(); diff --git a/snapshot/posix/timezone.cc b/snapshot/posix/timezone.cc index c413d7080f..e4b52081d1 100644 --- a/snapshot/posix/timezone.cc +++ b/snapshot/posix/timezone.cc @@ -40,7 +40,7 @@ void TimeZone(const timeval& snapshot_time, bool found_transition = false; long probe_gmtoff = local.tm_gmtoff; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // Some versions of the timezone database on Android have incorrect // information (e.g. Asia/Kolkata and Pacific/Honolulu). These timezones set // daylight to a non-zero value and return incorrect, >= 0 values for tm_isdst @@ -105,14 +105,14 @@ void TimeZone(const timeval& snapshot_time, } else { *daylight_name = tzname[0]; *dst_status = SystemSnapshot::kDoesNotObserveDaylightSavingTime; -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // timezone is more reliably set correctly on Android. *standard_offset_seconds = -timezone; *daylight_offset_seconds = -timezone; #else *standard_offset_seconds = local.tm_gmtoff; *daylight_offset_seconds = local.tm_gmtoff; -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) } } diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index 0bdea432b0..f6ef1efa5f 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -25,7 +25,7 @@ #include "util/misc/address_sanitizer.h" #include "util/numeric/safe_assignment.h" -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include #include "snapshot/linux/process_snapshot_linux.h" diff --git a/snapshot/sanitized/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc index 425ec7528d..933bc923e7 100644 --- a/snapshot/sanitized/sanitization_information_test.cc +++ b/snapshot/sanitized/sanitization_information_test.cc @@ -20,7 +20,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_linux.h" -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #endif diff --git a/snapshot/x86/cpuid_reader.cc b/snapshot/x86/cpuid_reader.cc index 583405844f..c1bd837c4d 100644 --- a/snapshot/x86/cpuid_reader.cc +++ b/snapshot/x86/cpuid_reader.cc @@ -16,12 +16,13 @@ #include +#include "build/build_config.h" #include "snapshot/cpu_context.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #include -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) #if defined(ARCH_CPU_X86_FAMILY) @@ -101,7 +102,7 @@ bool CpuidReader::SupportsDAZ() const { using Fxsave = CPUContextX86_64::Fxsave; #endif -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) __declspec(align(16)) Fxsave fxsave = {}; #else Fxsave fxsave __attribute__((aligned(16))) = {}; @@ -111,7 +112,7 @@ bool CpuidReader::SupportsDAZ() const { static_assert(offsetof(decltype(fxsave), mxcsr_mask) == 28, "mxcsr_mask offset"); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) _fxsave(&fxsave); #else asm("fxsave %0" : "=m"(fxsave)); @@ -122,13 +123,13 @@ bool CpuidReader::SupportsDAZ() const { } void CpuidReader::Cpuid(uint32_t cpuinfo[4], uint32_t leaf) const { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) __cpuid(reinterpret_cast(cpuinfo), leaf); #else asm("cpuid" : "=a"(cpuinfo[0]), "=b"(cpuinfo[1]), "=c"(cpuinfo[2]), "=d"(cpuinfo[3]) : "a"(leaf), "b"(0), "c"(0), "d"(0)); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } } // namespace internal diff --git a/test/errors.cc b/test/errors.cc index 1484506256..1f14db28ca 100644 --- a/test/errors.cc +++ b/test/errors.cc @@ -20,9 +20,9 @@ #include "base/strings/stringprintf.h" #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include "base/posix/safe_strerror.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include #endif @@ -31,10 +31,10 @@ namespace crashpad { namespace test { std::string ErrnoMessage(int err, const std::string& base) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) std::string err_as_string = base::safe_strerror(errno); const char* err_string = err_as_string.c_str(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) char err_string[256]; strerror_s(err_string, errno); #endif @@ -49,7 +49,7 @@ std::string ErrnoMessage(const std::string& base) { return ErrnoMessage(errno, base); } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) std::string ErrorMessage(const std::string& base) { return base::StringPrintf( "%s%s%s", diff --git a/test/errors.h b/test/errors.h index 471fbb5f7b..5be04f1b9b 100644 --- a/test/errors.h +++ b/test/errors.h @@ -67,7 +67,7 @@ std::string ErrnoMessage(int err, const std::string& base = std::string()); //! a colon. std::string ErrnoMessage(const std::string& base = std::string()); -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief Formats an error message using `GetLastError()`. //! //! The returned string will combine the \a base string, if supplied, with a diff --git a/test/file.cc b/test/file.cc index 04b4625f16..a0ec470d70 100644 --- a/test/file.cc +++ b/test/file.cc @@ -25,11 +25,11 @@ namespace crashpad { namespace test { bool FileExists(const base::FilePath& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) struct stat st; int rv = lstat(path.value().c_str(), &st); static constexpr char stat_function[] = "lstat"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) struct _stat st; int rv = _wstat(path.value().c_str(), &st); static constexpr char stat_function[] = "_wstat"; @@ -45,11 +45,11 @@ bool FileExists(const base::FilePath& path) { } FileOffset FileSize(const base::FilePath& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) struct stat st; int rv = lstat(path.value().c_str(), &st); static constexpr char stat_function[] = "lstat"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) struct _stati64 st; int rv = _wstati64(path.value().c_str(), &st); static constexpr char stat_function[] = "_wstati64"; diff --git a/test/filesystem.cc b/test/filesystem.cc index 39b864819b..a43421206e 100644 --- a/test/filesystem.cc +++ b/test/filesystem.cc @@ -22,6 +22,7 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/scoped_temp_dir.h" @@ -29,11 +30,11 @@ #include "util/file/filesystem.h" #include "util/misc/time.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include #include "base/posix/eintr_wrapper.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #endif @@ -42,7 +43,7 @@ namespace test { namespace { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Detects the flags necessary to create symbolic links and stores them in // |flags| if non-nullptr, and returns true on success. If symbolic links can’t @@ -89,7 +90,7 @@ bool SymbolicLinkFlags(DWORD* flags) { return true; } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace @@ -101,14 +102,14 @@ bool CreateFile(const base::FilePath& file) { } bool PathExists(const base::FilePath& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) struct stat st; if (lstat(path.value().c_str(), &st) != 0) { EXPECT_EQ(errno, ENOENT) << ErrnoMessage("lstat ") << path.value(); return false; } return true; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) if (GetFileAttributes(path.value().c_str()) == INVALID_FILE_ATTRIBUTES) { EXPECT_EQ(GetLastError(), static_cast(ERROR_FILE_NOT_FOUND)) << ErrorMessage("GetFileAttributes ") << base::WideToUTF8(path.value()); @@ -120,7 +121,7 @@ bool PathExists(const base::FilePath& path) { bool SetFileModificationTime(const base::FilePath& path, const timespec& mtime) { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // utimensat() isn't available on macOS until 10.13, so lutimes() is used // instead. struct stat st; @@ -136,7 +137,7 @@ bool SetFileModificationTime(const base::FilePath& path, return false; } return true; -#elif defined(OS_POSIX) +#elif BUILDFLAG(IS_POSIX) timespec times[2]; times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; @@ -147,7 +148,7 @@ bool SetFileModificationTime(const base::FilePath& path, return false; } return true; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) DWORD flags = FILE_FLAG_OPEN_REPARSE_POINT; if (IsDirectory(path, true)) { // required for directory handles @@ -172,22 +173,22 @@ bool SetFileModificationTime(const base::FilePath& path, return false; } return true; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) bool CanCreateSymbolicLinks() { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) return true; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return SymbolicLinkFlags(nullptr); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } bool CreateSymbolicLink(const base::FilePath& target_path, const base::FilePath& symlink_path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int rv = HANDLE_EINTR( symlink(target_path.value().c_str(), symlink_path.value().c_str())); if (rv != 0) { @@ -195,7 +196,7 @@ bool CreateSymbolicLink(const base::FilePath& target_path, return false; } return true; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) DWORD symbolic_link_flags = 0; SymbolicLinkFlags(&symbolic_link_flags); if (!::CreateSymbolicLink( @@ -208,10 +209,10 @@ bool CreateSymbolicLink(const base::FilePath& target_path, return false; } return true; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) } // namespace test } // namespace crashpad diff --git a/test/filesystem.h b/test/filesystem.h index 516335bb7c..683213689b 100644 --- a/test/filesystem.h +++ b/test/filesystem.h @@ -37,7 +37,7 @@ bool PathExists(const base::FilePath& path); //! \return `true` on success. Otherwise `false` with a message logged. bool SetFileModificationTime(const base::FilePath& path, const timespec& mtime); -#if !defined(OS_FUCHSIA) || DOXYGEN +#if !BUILDFLAG(IS_FUCHSIA) || DOXYGEN // There are no symbolic links on Fuchsia. Don’t bother declaring or defining // symbolic link-related functions at all, because it’s an error to even pretend // that symbolic links might be available on Fuchsia. @@ -67,7 +67,7 @@ bool CanCreateSymbolicLinks(); bool CreateSymbolicLink(const base::FilePath& target_path, const base::FilePath& symlink_path); -#endif // !OS_FUCHSIA || DOXYGEN +#endif // !BUILDFLAG(IS_FUCHSIA) || DOXYGEN } // namespace test } // namespace crashpad diff --git a/test/gtest_death.h b/test/gtest_death.h index c67d334521..8142c3d130 100644 --- a/test/gtest_death.h +++ b/test/gtest_death.h @@ -19,13 +19,13 @@ #include "build/build_config.h" #include "gtest/gtest.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "test/mac/exception_swallower.h" #endif //! \file -#if defined(OS_MAC) || DOXYGEN +#if BUILDFLAG(IS_MAC) || DOXYGEN //! \brief Wraps the Google Test `ASSERT_DEATH_IF_SUPPORTED()` macro to make //! assertions about death caused by crashes. @@ -73,14 +73,14 @@ regex); \ } while (false) -#else // OS_MAC +#else // BUILDFLAG(IS_MAC) #define ASSERT_DEATH_CRASH(statement, regex) \ ASSERT_DEATH_IF_SUPPORTED(statement, regex) #define EXPECT_DEATH_CRASH(statement, regex) \ EXPECT_DEATH_IF_SUPPORTED(statement, regex) -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) #if !(!defined(MINI_CHROMIUM_BASE_LOGGING_H_) && \ defined(OFFICIAL_BUILD) && \ diff --git a/test/gtest_main.cc b/test/gtest_main.cc index c67b8e24bb..04c539b770 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -22,17 +22,17 @@ #include "gmock/gmock.h" #endif // CRASHPAD_TEST_LAUNCHER_GOOGLEMOCK -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include "util/linux/initial_signal_dispositions.h" -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) #include "test/ios/google_test_setup.h" #endif -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include "test/win/win_child_process.h" -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) #if defined(CRASHPAD_IS_IN_CHROMIUM) #include "base/bind.h" @@ -42,7 +42,7 @@ namespace { -#if !defined(OS_IOS) +#if !BUILDFLAG(IS_IOS) bool GetChildTestFunctionName(std::string* child_func_name) { constexpr size_t arg_length = sizeof(crashpad::test::internal::kChildTestFunction) - 1; @@ -55,38 +55,38 @@ bool GetChildTestFunctionName(std::string* child_func_name) { } return false; } -#endif // !OS_IOS +#endif // !BUILDFLAG(IS_IOS) } // namespace int main(int argc, char* argv[]) { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) crashpad::InitializeSignalDispositions(); -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) crashpad::test::InitializeMainArguments(argc, argv); -#if !defined(OS_IOS) +#if !BUILDFLAG(IS_IOS) std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { return crashpad::test::internal::CheckedInvokeMultiprocessChild( child_func_name); } -#endif // !OS_IOS +#endif // !BUILDFLAG(IS_IOS) #if defined(CRASHPAD_IS_IN_CHROMIUM) -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Chromium’s test launcher interferes with WinMultiprocess-based tests. Allow // their child processes to be launched by the standard Google Test-based test // runner. const bool use_chromium_test_launcher = !crashpad::test::WinChildProcess::IsChildProcess(); -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) constexpr bool use_chromium_test_launcher = false; -#else // OS_WIN +#else // BUILDFLAG(IS_WIN) constexpr bool use_chromium_test_launcher = true; -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) if (use_chromium_test_launcher) { // This supports --test-launcher-summary-output, which writes a JSON file @@ -115,7 +115,7 @@ int main(int argc, char* argv[]) { CRASHPAD_TEST_LAUNCHER_GOOGLEMOCK #endif // CRASHPAD_TEST_LAUNCHER_GOOGLEMOCK -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // iOS needs to run tests within the context of an app, so call a helper that // invokes UIApplicationMain(). The application delegate will call // RUN_ALL_TESTS() and exit before returning control to this function. diff --git a/test/multiprocess.h b/test/multiprocess.h index ca48ce80af..dd96a0fe10 100644 --- a/test/multiprocess.h +++ b/test/multiprocess.h @@ -28,7 +28,7 @@ namespace internal { struct MultiprocessInfo; } // namespace internal -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) using ReturnCodeType = int64_t; #else using ReturnCodeType = int; @@ -55,13 +55,13 @@ class Multiprocess { //! that call `exit()` or `_exit()`. kTerminationNormal = false, -#if !defined(OS_FUCHSIA) // There are no signals on Fuchsia. +#if !BUILDFLAG(IS_FUCHSIA) // There are no signals on Fuchsia. //! \brief The child terminated by signal. //! //! Signal termination happens as a result of a crash, a call to `abort()`, //! assertion failure (including Google Test assertions), etc. kTerminationSignal, -#endif // !defined(OS_FUCHSIA) +#endif // !BUILDFLAG(IS_FUCHSIA) }; Multiprocess(); @@ -104,11 +104,11 @@ class Multiprocess { void SetExpectedChildTermination(TerminationReason reason, ReturnCodeType code); -#if !defined(OS_WIN) +#if !BUILDFLAG(IS_WIN) //! \brief Sets termination reason and code appropriately for a child that //! terminates via `__builtin_trap()`. void SetExpectedChildTerminationBuiltinTrap(); -#endif // !OS_WIN +#endif // !BUILDFLAG(IS_WIN) protected: ~Multiprocess(); @@ -131,17 +131,17 @@ class Multiprocess { //! Subclass implementations may signal failure by raising their own fatal //! Google Test assertions. virtual void PreFork() -#if defined(OS_WIN) || defined(OS_FUCHSIA) +#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) = 0 -#endif // OS_WIN || OS_FUCHSIA +#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) ; -#if !defined(OS_WIN) && !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_FUCHSIA) //! \brief Returns the child process’ process ID. //! //! This method may only be called by the parent process. pid_t ChildPID() const; -#endif // !OS_WIN && !OS_FUCHSIA +#endif // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_FUCHSIA) //! \brief Returns the read pipe’s file handle. //! diff --git a/test/multiprocess_exec.cc b/test/multiprocess_exec.cc index cd9a32c0bb..805090d0aa 100644 --- a/test/multiprocess_exec.cc +++ b/test/multiprocess_exec.cc @@ -18,6 +18,7 @@ #include "base/check.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "test/main_arguments.h" #include "test/test_paths.h" #include "util/stdlib/map_insert.h" @@ -59,7 +60,7 @@ void MultiprocessExec::SetChildTestMainFunction( GetMainArguments().end()); rest.push_back(internal::kChildTestFunction + function_name); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Instead of using argv[0] on Windows, use the actual binary name. This is // necessary because if originally the test isn't run with ".exe" on the // command line, then argv[0] also won't include ".exe". This argument is used diff --git a/test/multiprocess_exec.h b/test/multiprocess_exec.h index a03f8c1ade..3be9b7a250 100644 --- a/test/multiprocess_exec.h +++ b/test/multiprocess_exec.h @@ -141,11 +141,11 @@ class MultiprocessExec : public Multiprocess { base::FilePath command_; std::vector arguments_; -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) std::vector argv_; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) std::wstring command_line_; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) }; } // namespace test diff --git a/test/multiprocess_exec_posix.cc b/test/multiprocess_exec_posix.cc index e14a3b88ad..fa87f08887 100644 --- a/test/multiprocess_exec_posix.cc +++ b/test/multiprocess_exec_posix.cc @@ -26,11 +26,11 @@ #include "util/misc/scoped_forbid_return.h" #include "util/posix/close_multiple.h" -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include #endif -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "util/mach/task_for_pid.h" #endif @@ -90,7 +90,7 @@ void MultiprocessExec::MultiprocessChild() { int rv; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) __fpurge(stdin); #else rv = fpurge(stdin); @@ -154,7 +154,7 @@ void MultiprocessExec::MultiprocessChild() { } ProcessType MultiprocessExec::ChildProcess() { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) return TaskForPID(ChildPID()); #else return ChildPID(); diff --git a/test/multiprocess_exec_test.cc b/test/multiprocess_exec_test.cc index fb77d642fb..8d8f1e2010 100644 --- a/test/multiprocess_exec_test.cc +++ b/test/multiprocess_exec_test.cc @@ -101,7 +101,7 @@ TEST(MultiprocessExec, MultiprocessExecSimpleChildReturnsNonZero) { exec.Run(); } -#if !defined(OS_WIN) +#if !BUILDFLAG(IS_WIN) CRASHPAD_CHILD_TEST_MAIN(BuiltinTrapChild) { __builtin_trap(); @@ -130,7 +130,7 @@ TEST(MultiprocessExec, BuiltinTrapTermination) { test.Run(); } -#endif // !OS_WIN +#endif // !BUILDFLAG(IS_WIN) } // namespace } // namespace test diff --git a/test/multiprocess_exec_test_child.cc b/test/multiprocess_exec_test_child.cc index 8c77015c1b..f74b585606 100644 --- a/test/multiprocess_exec_test_child.cc +++ b/test/multiprocess_exec_test_child.cc @@ -22,19 +22,19 @@ #include "base/logging.h" #include "build/build_config.h" -#if defined(OS_POSIX) -#if !defined(OS_FUCHSIA) +#if BUILDFLAG(IS_POSIX) +#if !BUILDFLAG(IS_FUCHSIA) #include -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #endif int main(int argc, char* argv[]) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // getrlimit() is not implemented on Fuchsia. By construction, the child only // receieves specific fds that it's given, but check low values as mild // verification. @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) { LOG(FATAL) << "getrlimit"; } int last_fd = static_cast(rlimit_nofile.rlim_cur); -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) // Make sure that there’s nothing open at any FD higher than 3. All FDs other // than stdin, stdout, and stderr should have been closed prior to or at @@ -69,7 +69,7 @@ int main(int argc, char* argv[]) { if (rv != 1) { LOG(FATAL) << "write"; } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) // TODO(scottmg): Verify that only the handles we expect to be open, are. // Read a byte from stdin, expecting it to be a specific value. @@ -89,7 +89,7 @@ int main(int argc, char* argv[]) { bytes_written != 1) { LOG(FATAL) << "WriteFile"; } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) return 0; } diff --git a/test/multiprocess_posix.cc b/test/multiprocess_posix.cc index c16aa08f7b..f1b138f6cc 100644 --- a/test/multiprocess_posix.cc +++ b/test/multiprocess_posix.cc @@ -33,7 +33,7 @@ #include "util/misc/scoped_forbid_return.h" #include "util/posix/signals.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "test/mac/exception_swallower.h" #endif @@ -73,7 +73,7 @@ void Multiprocess::Run() { ASSERT_NO_FATAL_FAILURE(PreFork()); -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // If the child is expected to crash, set up an exception swallower to swallow // the exception instead of allowing it to be seen by the system’s crash // reporter. @@ -81,7 +81,7 @@ void Multiprocess::Run() { if (reason_ == kTerminationSignal && Signals::IsCrashSignal(code_)) { exception_swallower.reset(new ExceptionSwallower()); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) pid_t pid = fork(); ASSERT_GE(pid, 0) << ErrnoMessage("fork"); @@ -139,15 +139,15 @@ void Multiprocess::Run() { ADD_FAILURE() << message; } } else { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (exception_swallower.get()) { ExceptionSwallower::SwallowExceptions(); } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) if (reason_ == kTerminationSignal && Signals::IsCrashSignal(code_)) { Signals::InstallDefaultHandler(code_); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) RunChild(); } diff --git a/test/process_type.cc b/test/process_type.cc index f6eec36ab1..7c6f88fa9b 100644 --- a/test/process_type.cc +++ b/test/process_type.cc @@ -14,9 +14,11 @@ #include "test/process_type.h" -#if defined(OS_FUCHSIA) +#include "build/build_config.h" + +#if BUILDFLAG(IS_FUCHSIA) #include -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include #endif @@ -24,13 +26,13 @@ namespace crashpad { namespace test { ProcessType GetSelfProcess() { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) return zx::process::self(); -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) return getpid(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return GetCurrentProcess(); -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) return mach_task_self(); #endif } diff --git a/test/process_type.h b/test/process_type.h index cacac04fb0..a1c727cb0c 100644 --- a/test/process_type.h +++ b/test/process_type.h @@ -17,28 +17,28 @@ #include "build/build_config.h" -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) #include -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) #include #endif namespace crashpad { namespace test { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) using ProcessType = zx::unowned_process; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \ - DOXYGEN +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) || DOXYGEN //! \brief Alias for platform-specific type to represent a process. using ProcessType = pid_t; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using ProcessType = HANDLE; -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) using ProcessType = task_t; #else #error Port. diff --git a/test/scoped_module_handle.cc b/test/scoped_module_handle.cc index df246fcf4c..ff8e0bd9c1 100644 --- a/test/scoped_module_handle.cc +++ b/test/scoped_module_handle.cc @@ -15,17 +15,18 @@ #include "test/scoped_module_handle.h" #include "base/logging.h" +#include "build/build_config.h" namespace crashpad { namespace test { // static void ScopedModuleHandle::Impl::Close(ModuleHandle handle) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) if (dlclose(handle) != 0) { LOG(ERROR) << "dlclose: " << dlerror(); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) if (!FreeLibrary(handle)) { PLOG(ERROR) << "FreeLibrary"; } diff --git a/test/scoped_module_handle.h b/test/scoped_module_handle.h index 0e96c9510b..1a8ed1bf94 100644 --- a/test/scoped_module_handle.h +++ b/test/scoped_module_handle.h @@ -17,9 +17,9 @@ #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #endif @@ -36,13 +36,13 @@ class ScopedModuleHandle { Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) using ModuleHandle = void*; static void* LookUpSymbol(ModuleHandle handle, const char* symbol_name) { return dlsym(handle, symbol_name); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using ModuleHandle = HMODULE; static void* LookUpSymbol(ModuleHandle handle, const char* symbol_name) { diff --git a/test/scoped_temp_dir_posix.cc b/test/scoped_temp_dir_posix.cc index 38aa4fb84f..848ab5692a 100644 --- a/test/scoped_temp_dir_posix.cc +++ b/test/scoped_temp_dir_posix.cc @@ -42,7 +42,7 @@ base::FilePath ScopedTempDir::CreateTemporaryDirectory() { if (tmpdir && tmpdir[0] != '\0') { dir.assign(tmpdir); } else { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) dir.assign("/data/local/tmp"); #else dir.assign("/tmp"); diff --git a/test/scoped_temp_dir_test.cc b/test/scoped_temp_dir_test.cc index 9ad801f7f0..3b5a31642c 100644 --- a/test/scoped_temp_dir_test.cc +++ b/test/scoped_temp_dir_test.cc @@ -23,26 +23,26 @@ #include "test/errors.h" #include "test/file.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace crashpad { namespace test { namespace { void CreateFile(const base::FilePath& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int fd = HANDLE_EINTR(creat(path.value().c_str(), 0644)); ASSERT_GE(fd, 0) << ErrnoMessage("creat") << " " << path.value(); // gcc refuses to compile ASSERT_EQ(IGNORE_EINTR(close(fd)), 0). int close_rv = IGNORE_EINTR(close(fd)); ASSERT_EQ(close_rv, 0) << ErrnoMessage("close") << " " << path.value(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int fd = _wcreat(path.value().c_str(), _S_IREAD | _S_IWRITE); ASSERT_GE(fd, 0) << ErrnoMessage("_wcreat") << " " << path.value(); ASSERT_EQ(_close(fd), 0) << ErrnoMessage("_close") << " " << path.value(); @@ -53,10 +53,10 @@ void CreateFile(const base::FilePath& path) { } void CreateDirectory(const base::FilePath& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) ASSERT_EQ(mkdir(path.value().c_str(), 0755), 0) << ErrnoMessage("mkdir") << " " << path.value(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ASSERT_EQ(_wmkdir(path.value().c_str()), 0) << ErrnoMessage("_wmkdir") << " " << path.value(); #else diff --git a/test/test_paths.cc b/test/test_paths.cc index 475e2b0193..c55aa647bf 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -31,7 +31,7 @@ bool IsTestDataRoot(const base::FilePath& candidate) { candidate.Append(FILE_PATH_LITERAL("test")) .Append(FILE_PATH_LITERAL("test_paths_test_data_root.txt")); -#if !defined(OS_WIN) +#if !BUILDFLAG(IS_WIN) struct stat stat_buf; int rv = stat(marker_path.value().c_str(), &stat_buf); #else @@ -43,16 +43,16 @@ bool IsTestDataRoot(const base::FilePath& candidate) { } base::FilePath TestDataRootInternal() { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) base::FilePath asset_path("/pkg/data"); if (!IsTestDataRoot(asset_path)) { LOG(WARNING) << "test data root seems invalid, continuing anyway"; } return asset_path; -#else // defined(OS_FUCHSIA) -#if !defined(OS_WIN) +#else // BUILDFLAG(IS_FUCHSIA) +#if !BUILDFLAG(IS_WIN) const char* environment_value = getenv("CRASHPAD_TEST_DATA_ROOT"); -#else // defined(OS_WIN) +#else // BUILDFLAG(IS_WIN) const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_DATA_ROOT"); #endif @@ -67,21 +67,21 @@ base::FilePath TestDataRootInternal() { base::FilePath executable_path; if (Paths::Executable(&executable_path)) { -#if defined(OS_IOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) // On Android and iOS, test data is in a crashpad_test_data directory // adjacent to the main executable. On iOS, this refers to the main // executable file inside the .app bundle, so crashpad_test_data is also // inside the bundle. base::FilePath candidate = executable_path.DirName() .Append("crashpad_test_data"); -#else // OS_IOS || OS_ANDRID +#else // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDRID) // In a standalone build, the test executable is usually at // out/{Debug,Release} relative to the Crashpad root. base::FilePath candidate = base::FilePath(executable_path.DirName() .Append(base::FilePath::kParentDirectory) .Append(base::FilePath::kParentDirectory)); -#endif // OS_IOS || OS_ANDROID +#endif // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID) if (IsTestDataRoot(candidate)) { return candidate; } @@ -104,10 +104,10 @@ base::FilePath TestDataRootInternal() { } return base::FilePath(base::FilePath::kCurrentDirectory); -#endif // defined(OS_FUCHSIA) +#endif // BUILDFLAG(IS_FUCHSIA) } -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) // Returns the pathname of a directory containing 32-bit test build output. // @@ -122,7 +122,7 @@ base::FilePath Output32BitDirectory() { return base::FilePath(environment_value); } -#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS) +#endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) } // namespace @@ -139,10 +139,10 @@ base::FilePath TestPaths::Executable() { // static base::FilePath TestPaths::ExpectedExecutableBasename( const base::FilePath::StringType& name) { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // Apps in Fuchsia packages are always named "app". return base::FilePath("app"); -#else // OS_FUCHSIA +#else // BUILDFLAG(IS_FUCHSIA) #if defined(CRASHPAD_IS_IN_CHROMIUM) base::FilePath::StringType executable_name( FILE_PATH_LITERAL("crashpad_tests")); @@ -150,12 +150,12 @@ base::FilePath TestPaths::ExpectedExecutableBasename( base::FilePath::StringType executable_name(name); #endif // CRASHPAD_IS_IN_CHROMIUM -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) executable_name += FILE_PATH_LITERAL(".exe"); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) return base::FilePath(executable_name); -#endif // OS_FUCHSIA +#endif // BUILDFLAG(IS_FUCHSIA) } // static @@ -177,17 +177,17 @@ base::FilePath TestPaths::BuildArtifact( directory = Executable().DirName(); break; -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) case Architecture::k32Bit: directory = Output32BitDirectory(); CHECK(!directory.empty()); break; -#endif // OS_WIN && ARCH_CPU_64_BITS +#endif // BUILDFLAG(IS_WIN) && ARCH_CPU_64_BITS } base::FilePath::StringType test_name = FILE_PATH_LITERAL("crashpad_") + module + FILE_PATH_LITERAL("_test"); -#if !defined(CRASHPAD_IS_IN_CHROMIUM) && !defined(OS_FUCHSIA) +#if !defined(CRASHPAD_IS_IN_CHROMIUM) && !BUILDFLAG(IS_FUCHSIA) CHECK(Executable().BaseName().RemoveFinalExtension().value() == test_name); #endif // !CRASHPAD_IS_IN_CHROMIUM @@ -197,21 +197,21 @@ base::FilePath TestPaths::BuildArtifact( break; case FileType::kExecutable: -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) extension = FILE_PATH_LITERAL(".exe"); -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) directory = base::FilePath(FILE_PATH_LITERAL("/pkg/bin")); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) break; case FileType::kLoadableModule: -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) extension = FILE_PATH_LITERAL(".dll"); -#else // OS_WIN +#else // BUILDFLAG(IS_WIN) extension = FILE_PATH_LITERAL(".so"); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // TODO(scottmg): .so files are currently deployed into /boot/lib, where // they'll be found (without a path) by the loader. Application packaging // infrastructure is in progress, so this will likely change again in the @@ -232,14 +232,14 @@ base::FilePath TestPaths::BuildArtifact( extension); } -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) // static bool TestPaths::Has32BitBuildArtifacts() { return !Output32BitDirectory().empty(); } -#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS) +#endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS) } // namespace test } // namespace crashpad diff --git a/test/test_paths.h b/test/test_paths.h index 72bb155392..0fc021e139 100644 --- a/test/test_paths.h +++ b/test/test_paths.h @@ -49,14 +49,14 @@ class TestPaths { //! architecture as the running process. kDefault = 0, -#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN +#if (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN //! \brief The 32-bit variant is requested. //! //! On Windows, when running 64-bit code, the 32-bit variant can be //! requested. Before doing so, Has32BitBuildArtifacts() must be called and //! must return `true`. Otherwise, execution will be aborted. k32Bit, -#endif // OS_WIN && ARCH_CPU_64_BITS +#endif // BUILDFLAG(IS_WIN) && ARCH_CPU_64_BITS }; TestPaths() = delete; @@ -128,7 +128,7 @@ class TestPaths { FileType file_type, Architecture architecture = Architecture::kDefault); -#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN +#if (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN //! \return `true` if 32-bit build artifacts are available. //! //! Tests that require the use of 32-bit build output should call this @@ -142,7 +142,7 @@ class TestPaths { //! can be found its own directory, and located by calling BuildArtifact() //! with Architecture::kDefault. static bool Has32BitBuildArtifacts(); -#endif // OS_WIN && ARCH_CPU_64_BITS +#endif // BUILDFLAG(IS_WIN) && ARCH_CPU_64_BITS }; } // namespace test diff --git a/tools/base94_encoder.cc b/tools/base94_encoder.cc index 1b184e9fb8..b0f7e0e328 100644 --- a/tools/base94_encoder.cc +++ b/tools/base94_encoder.cc @@ -24,6 +24,7 @@ namespace crashpad { namespace { void Usage(const base::FilePath& me) { + // clang-format off fprintf(stderr, "Usage: %" PRFilePath " [options] \n" "Encode/Decode the given file\n" @@ -34,6 +35,7 @@ void Usage(const base::FilePath& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -117,12 +119,12 @@ int Base94EncoderMain(int argc, char* argv[]) { } // namespace } // namespace crashpad -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return crashpad::Base94EncoderMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, crashpad::Base94EncoderMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index e9927bd40c..bbe6f7dd95 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -44,6 +44,7 @@ namespace crashpad { namespace { void Usage(const base::FilePath& me) { + // clang-format off fprintf(stderr, "Usage: %" PRFilePath " [OPTION]... PID\n" "Operate on Crashpad crash report databases.\n" @@ -66,6 +67,7 @@ void Usage(const base::FilePath& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -619,12 +621,12 @@ int DatabaseUtilMain(int argc, char* argv[]) { } // namespace } // namespace crashpad -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return crashpad::DatabaseUtilMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, crashpad::DatabaseUtilMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/tools/crashpad_http_upload.cc b/tools/crashpad_http_upload.cc index 624aaa715e..1470b410eb 100644 --- a/tools/crashpad_http_upload.cc +++ b/tools/crashpad_http_upload.cc @@ -22,6 +22,7 @@ #include #include "base/files/file_path.h" +#include "build/build_config.h" #include "tools/tool_support.h" #include "util/file/file_reader.h" #include "util/file/file_writer.h" @@ -34,6 +35,7 @@ namespace crashpad { namespace { void Usage(const base::FilePath& me) { + // clang-format off fprintf(stderr, "Usage: %" PRFilePath " [OPTION]...\n" "Send an HTTP POST request.\n" @@ -45,6 +47,7 @@ void Usage(const base::FilePath& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -205,12 +208,12 @@ int HTTPUploadMain(int argc, char* argv[]) { } // namespace } // namespace crashpad -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return crashpad::HTTPUploadMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, crashpad::HTTPUploadMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index ab027b8795..ba561a583a 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -29,33 +29,34 @@ #include "util/process/process_id.h" #include "util/stdlib/string_number_conversion.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include #include "util/posix/drop_privileges.h" #endif -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include #include "base/mac/scoped_mach_port.h" #include "snapshot/mac/process_snapshot_mac.h" #include "util/mach/scoped_task_suspend.h" #include "util/mach/task_for_pid.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include "base/strings/utf_string_conversions.h" #include "snapshot/win/process_snapshot_win.h" #include "util/win/scoped_process_suspend.h" #include "util/win/xp_compat.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "snapshot/linux/process_snapshot_linux.h" #include "util/linux/direct_ptrace_connection.h" -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { namespace { void Usage(const base::FilePath& me) { + // clang-format off fprintf(stderr, "Usage: %" PRFilePath " [OPTION]... PID\n" "Generate a minidump file containing a snapshot of a running process.\n" @@ -65,6 +66,7 @@ void Usage(const base::FilePath& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -137,7 +139,7 @@ int GenerateDumpMain(int argc, char* argv[]) { return EXIT_FAILURE; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) task_t task = TaskForPID(options.pid); if (task == TASK_NULL) { return EXIT_FAILURE; @@ -155,14 +157,14 @@ int GenerateDumpMain(int argc, char* argv[]) { } LOG(WARNING) << "operating on myself"; } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ScopedKernelHANDLE process( OpenProcess(kXPProcessAllAccess, false, options.pid)); if (!process.is_valid()) { PLOG(ERROR) << "could not open process " << options.pid; return EXIT_FAILURE; } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) if (options.dump_path.empty()) { options.dump_path = base::StringPrintf("minidump.%" PRI_PROCESS_ID, @@ -170,24 +172,24 @@ int GenerateDumpMain(int argc, char* argv[]) { } { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) std::unique_ptr suspend; if (options.suspend) { suspend.reset(new ScopedTaskSuspend(task)); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) std::unique_ptr suspend; if (options.suspend) { suspend.reset(new ScopedProcessSuspend(process.get())); } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) ProcessSnapshotMac process_snapshot; if (!process_snapshot.Initialize(task)) { return EXIT_FAILURE; } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) ProcessSnapshotWin process_snapshot; if (!process_snapshot.Initialize(process.get(), options.suspend @@ -197,7 +199,7 @@ int GenerateDumpMain(int argc, char* argv[]) { 0)) { return EXIT_FAILURE; } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // TODO(jperaza): https://crashpad.chromium.org/bug/30. DirectPtraceConnection task; if (!task.Initialize(options.pid)) { @@ -207,7 +209,7 @@ int GenerateDumpMain(int argc, char* argv[]) { if (!process_snapshot.Initialize(&task)) { return EXIT_FAILURE; } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) FileWriter file_writer; base::FilePath dump_path( @@ -236,12 +238,12 @@ int GenerateDumpMain(int argc, char* argv[]) { } // namespace } // namespace crashpad -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int main(int argc, char* argv[]) { return crashpad::GenerateDumpMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain(argc, argv, crashpad::GenerateDumpMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/tools/mac/catch_exception_tool.cc b/tools/mac/catch_exception_tool.cc index 06fda23d4e..568672d781 100644 --- a/tools/mac/catch_exception_tool.cc +++ b/tools/mac/catch_exception_tool.cc @@ -181,6 +181,7 @@ class ExceptionServer final : public UniversalMachExcServer::Interface { }; void Usage(const std::string& me) { + // clang-format off fprintf(stderr, "Usage: %s -m SERVICE [OPTION]...\n" "Catch Mach exceptions and display information about them.\n" @@ -192,6 +193,7 @@ void Usage(const std::string& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.c_str()); + // clang-format on ToolSupport::UsageTail(me); } diff --git a/tools/mac/exception_port_tool.cc b/tools/mac/exception_port_tool.cc index 2fdc580018..60d841445d 100644 --- a/tools/mac/exception_port_tool.cc +++ b/tools/mac/exception_port_tool.cc @@ -311,6 +311,7 @@ bool SetExceptionPort(const ExceptionHandlerDescription* description, } void Usage(const std::string& me) { + // clang-format off fprintf(stderr, "Usage: %s [OPTION]... [COMMAND [ARG]...]\n" "View and change Mach exception ports, and run COMMAND if supplied.\n" @@ -343,6 +344,7 @@ void Usage(const std::string& me) { "The default DESCRIPTION is\n" " target=task,mask=CRASH,behavior=DEFAULT|MACH,flavor=NONE,handler=NULL\n", me.c_str()); + // clang-format on ToolSupport::UsageTail(me); } diff --git a/tools/mac/on_demand_service_tool.mm b/tools/mac/on_demand_service_tool.mm index 7b3e104169..ffb7920c8f 100644 --- a/tools/mac/on_demand_service_tool.mm +++ b/tools/mac/on_demand_service_tool.mm @@ -34,6 +34,7 @@ namespace { void Usage(const std::string& me) { + // clang-format off fprintf(stderr, "Usage: %s -L -l LABEL [OPTION]... COMMAND [ARG]...\n" " %s -U -l LABEL\n" @@ -48,6 +49,7 @@ void Usage(const std::string& me) { " --version output version information and exit\n", me.c_str(), me.c_str()); + // clang-format on ToolSupport::UsageTail(me); } diff --git a/tools/run_with_crashpad.cc b/tools/run_with_crashpad.cc index 5ef0edb685..487f378fa5 100644 --- a/tools/run_with_crashpad.cc +++ b/tools/run_with_crashpad.cc @@ -31,7 +31,7 @@ #include "util/stdlib/map_insert.h" #include "util/string/split_string.h" -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) #include #include #include @@ -43,16 +43,23 @@ namespace crashpad { namespace { void Usage(const std::string& me) { + // clang-format off fprintf(stderr, "Usage: %s [OPTION]... COMMAND [ARG]...\n" "Start a Crashpad handler and have it handle crashes from COMMAND.\n" "\n" -#if defined(OS_FUCHSIA) + // clang-format on +#if BUILDFLAG(IS_FUCHSIA) + // clang-format off "COMMAND is run via fdio_spawn, so must be a qualified path to the subprocess to\n" "be executed.\n" + // clang-format on #else + // clang-format off "COMMAND is run via execvp() so the PATH will be searched.\n" + // clang-format on #endif + // clang-format off "\n" " -h, --handler=HANDLER invoke HANDLER instead of crashpad_handler\n" " --annotation=KEY=VALUE passed to the handler as an --annotation argument\n" @@ -62,6 +69,7 @@ void Usage(const std::string& me) { " --help display this help and exit\n" " --version output version information and exit\n", me.c_str()); + // clang-format on ToolSupport::UsageTail(me); } @@ -189,7 +197,7 @@ int RunWithCrashpadMain(int argc, char* argv[]) { return kExitFailure; } -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // Fuchsia doesn't implement execvp(), launch with fdio_spawn here. zx_handle_t child = ZX_HANDLE_INVALID; zx_status_t status = fdio_spawn( diff --git a/tools/tool_support.cc b/tools/tool_support.cc index b453f6e87b..aa6a2d9e4e 100644 --- a/tools/tool_support.cc +++ b/tools/tool_support.cc @@ -21,6 +21,7 @@ #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "package.h" namespace crashpad { @@ -55,7 +56,7 @@ void ToolSupport::UsageHint(const base::FilePath& me, const char* hint) { me.value().c_str()); } -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) // static void ToolSupport::Version(const std::string& me) { Version(base::FilePath(me)); @@ -70,9 +71,9 @@ void ToolSupport::UsageTail(const std::string& me) { void ToolSupport::UsageHint(const std::string& me, const char* hint) { UsageHint(base::FilePath(me), hint); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // static int ToolSupport::Wmain(int argc, wchar_t* argv[], int (*entry)(int, char* [])) { @@ -87,26 +88,26 @@ int ToolSupport::Wmain(int argc, wchar_t* argv[], int (*entry)(int, char* [])) { return entry(argc, argv_as_utf8.get()); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) // static base::FilePath::StringType ToolSupport::CommandLineArgumentToFilePathStringType( const base::StringPiece& path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) return std::string(path.data(), path.size()); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return base::UTF8ToWide(path); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } // static std::string ToolSupport::FilePathToCommandLineArgument( const base::FilePath& file_path) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) return file_path.value(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return base::WideToUTF8(file_path.value()); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } } // namespace crashpad diff --git a/tools/tool_support.h b/tools/tool_support.h index fd4955e432..87db24dbb5 100644 --- a/tools/tool_support.h +++ b/tools/tool_support.h @@ -48,7 +48,7 @@ class ToolSupport { //! Optional, may be `nullptr`, in which case no hint will be presented. static void UsageHint(const base::FilePath& me, const char* hint); -#if defined(OS_POSIX) || DOXYGEN +#if BUILDFLAG(IS_POSIX) || DOXYGEN //! \copydoc Version static void Version(const std::string& me); @@ -57,15 +57,15 @@ class ToolSupport { //! \copydoc UsageHint static void UsageHint(const std::string& me, const char* hint); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief Converts \a argv `wchar_t` UTF-16 to UTF-8, and passes onwards to a //! UTF-8 entry point. //! //! \return The return value of \a entry. static int Wmain(int argc, wchar_t* argv[], int (*entry)(int, char*[])); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) //! \brief Converts a command line argument to the string type suitable for //! base::FilePath. diff --git a/util/file/directory_reader.h b/util/file/directory_reader.h index 096d120d63..ccde8b7173 100644 --- a/util/file/directory_reader.h +++ b/util/file/directory_reader.h @@ -18,13 +18,13 @@ #include "base/files/file_path.h" #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include "util/posix/scoped_dir.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include "util/win/scoped_handle.h" -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace crashpad { @@ -67,20 +67,20 @@ class DirectoryReader { //! logged. Result NextFile(base::FilePath* filename); -#if defined(OS_POSIX) || DOXYGEN +#if BUILDFLAG(IS_POSIX) || DOXYGEN //! \brief Returns the file descriptor associated with this reader, logging a //! message and returning -1 on error. int DirectoryFD(); #endif private: -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) ScopedDIR dir_; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) WIN32_FIND_DATA find_data_; ScopedSearchHANDLE handle_; bool first_entry_; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) }; } // namespace crashpad diff --git a/util/file/directory_reader_test.cc b/util/file/directory_reader_test.cc index 5d09c6fb3d..e1dcee2fa6 100644 --- a/util/file/directory_reader_test.cc +++ b/util/file/directory_reader_test.cc @@ -19,6 +19,7 @@ #include "base/files/file_path.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/filesystem.h" #include "test/scoped_temp_dir.h" @@ -42,7 +43,7 @@ TEST(DirectoryReader, BadPaths) { reader.Open(temp_dir.path().Append(FILE_PATH_LITERAL("doesntexist")))); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(DirectoryReader, BadPaths_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -63,7 +64,7 @@ TEST(DirectoryReader, BadPaths_SymbolicLinks) { EXPECT_FALSE(reader.Open(link)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(DirectoryReader, EmptyDirectory) { ScopedTempDir temp_dir; @@ -103,7 +104,7 @@ void TestFilesAndDirectories(bool symbolic_links) { ASSERT_TRUE( CreateFile(temp_dir.path().Append(directory).Append(nested_file))); -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) if (symbolic_links) { base::FilePath link(FILE_PATH_LITERAL("link")); @@ -118,7 +119,7 @@ void TestFilesAndDirectories(bool symbolic_links) { EXPECT_TRUE(expected_files.insert(dangling).second); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) std::set files; DirectoryReader reader; @@ -138,7 +139,7 @@ TEST(DirectoryReader, FilesAndDirectories) { TestFilesAndDirectories(false); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -148,7 +149,7 @@ TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) { TestFilesAndDirectories(true); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) } // namespace } // namespace test diff --git a/util/file/file_io.h b/util/file/file_io.h index 526debddae..6a6a58653a 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -21,9 +21,9 @@ #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include "base/files/scoped_file.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include "util/win/scoped_handle.h" #endif @@ -34,7 +34,7 @@ class FilePath; namespace crashpad { -#if defined(OS_POSIX) || DOXYGEN +#if BUILDFLAG(IS_POSIX) || DOXYGEN //! \brief Platform-specific alias for a low-level file handle. using FileHandle = int; @@ -51,7 +51,7 @@ using FileOperationResult = ssize_t; //! \brief A value that can never be a valid FileHandle. const FileHandle kInvalidFileHandle = -1; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using FileHandle = HANDLE; using FileOffset = LONGLONG; @@ -132,7 +132,7 @@ enum class StdioStream { namespace internal { -#if defined(OS_POSIX) || DOXYGEN +#if BUILDFLAG(IS_POSIX) || DOXYGEN //! \brief The name of the native read function used by ReadFile(). //! @@ -148,7 +148,7 @@ constexpr char kNativeReadFunctionName[] = "read"; //! \sa kNativeReadFunctionName constexpr char kNativeWriteFunctionName[] = "write"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) constexpr char kNativeReadFunctionName[] = "ReadFile"; constexpr char kNativeWriteFunctionName[] = "WriteFile"; @@ -422,7 +422,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions); -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) //! \brief Opens an in-memory file for input and output. //! //! This function first attempts to open the file with `memfd_create()`. If @@ -444,7 +444,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, //! \sa LoggingOpenFileForWrite //! \sa LoggingOpenFileForReadAndWrite FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name); -#endif // OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation //! fails. @@ -461,7 +461,7 @@ FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, // Fuchsia does not currently support any sort of file locking. See // https://crashpad.chromium.org/bug/196 and // https://crashpad.chromium.org/bug/217. -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) //! \brief Locks the given \a file using `flock()` on POSIX or `LockFileEx()` on //! Windows. @@ -500,7 +500,7 @@ FileLockingResult LoggingLockFile(FileHandle file, //! \return `true` on success, or `false` and a message will be logged. bool LoggingUnlockFile(FileHandle file); -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) //! \brief Wraps `lseek()` or `SetFilePointerEx()`. Logs an error if the //! operation fails. diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index 119a2fcf67..5276b36dac 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -72,7 +72,7 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, const base::FilePath& path, FileWriteMode mode, FilePermissions permissions) { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // O_NOCTTY is invalid on Fuchsia, and O_CLOEXEC isn't necessary. int flags = 0; #else @@ -120,7 +120,7 @@ FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size) { FileHandle OpenFileForRead(const base::FilePath& path) { int flags = O_RDONLY; -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) // O_NOCTTY is invalid on Fuchsia, and O_CLOEXEC isn't necessary. flags |= O_NOCTTY | O_CLOEXEC; #endif @@ -153,7 +153,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, return fd; } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name) { DCHECK(name.value().find('/') == std::string::npos); @@ -208,7 +208,7 @@ FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, return fd; } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) FileLockingResult LoggingLockFile(FileHandle file, FileLocking locking, @@ -234,7 +234,7 @@ bool LoggingUnlockFile(FileHandle file) { return rv == 0; } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) FileOffset LoggingSeekFile(FileHandle file, FileOffset offset, int whence) { off_t rv = lseek(file, offset, whence); diff --git a/util/file/file_io_test.cc b/util/file/file_io_test.cc index abfef12916..f970e3564b 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -22,6 +22,7 @@ #include "base/atomicops.h" #include "base/cxx17_backports.h" #include "base/files/file_path.h" +#include "build/build_config.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/errors.h" @@ -474,7 +475,7 @@ TEST(FileIO, LoggingOpenFileForReadAndWrite) { TestOpenFileForWrite(LoggingOpenFileForReadAndWrite); } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) TEST(FileIO, LoggingOpenMemoryFileForReadAndWrite) { ScopedFileHandle handle( LoggingOpenMemoryFileForReadAndWrite(base::FilePath("memfile"))); @@ -489,7 +490,7 @@ TEST(FileIO, LoggingOpenMemoryFileForReadAndWrite) { ASSERT_TRUE(LoggingReadFileExactly(handle.get(), buffer, sizeof(buffer))); EXPECT_EQ(memcmp(buffer, kTestData, sizeof(buffer)), 0); } -#endif // OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) enum class ReadOrWrite : bool { kRead, @@ -545,7 +546,7 @@ TEST(FileIO, FileShareMode_Write_Write) { // Fuchsia does not currently support any sort of file locking. See // https://crashpad.chromium.org/bug/196 and // https://crashpad.chromium.org/bug/217. -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(FileIO, MultipleSharedLocks) { ScopedTempDir temp_dir; @@ -720,7 +721,7 @@ TEST(FileIO, ExclusiveVsExclusivesNonBlocking) { EXPECT_TRUE(LoggingUnlockFile(handle2.get())); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(FileIO, FileSizeByHandle) { EXPECT_EQ(LoggingFileSizeByHandle(kInvalidFileHandle), -1); @@ -742,9 +743,9 @@ TEST(FileIO, FileSizeByHandle) { FileHandle FileHandleForFILE(FILE* file) { int fd = fileno(file); -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) return fd; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return reinterpret_cast(_get_osfhandle(fd)); #else #error Port diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index 73fe708796..b6f50eb78f 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -25,22 +25,22 @@ #include "build/build_config.h" #include "util/misc/implicit_cast.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include #include #include "base/posix/eintr_wrapper.h" -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace crashpad { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) // Ensure type compatibility between WritableIoVec and iovec. static_assert(sizeof(WritableIoVec) == sizeof(iovec), "WritableIoVec size"); static_assert(offsetof(WritableIoVec, iov_base) == offsetof(iovec, iov_base), "WritableIoVec base offset"); static_assert(offsetof(WritableIoVec, iov_len) == offsetof(iovec, iov_len), "WritableIoVec len offset"); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) WeakFileHandleFileWriter::WeakFileHandleFileWriter(FileHandle file_handle) : file_handle_(file_handle) { @@ -62,7 +62,7 @@ bool WeakFileHandleFileWriter::WriteIoVec(std::vector* iovecs) { return false; } -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) ssize_t size = 0; for (const WritableIoVec& iov : *iovecs) { @@ -79,7 +79,7 @@ bool WeakFileHandleFileWriter::WriteIoVec(std::vector* iovecs) { iovec* iov = reinterpret_cast(&(*iovecs)[0]); size_t remaining_iovecs = iovecs->size(); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // Android does not expose the IOV_MAX macro, but makes its value available // via sysconf(). See Android 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf(). // Bionic defines IOV_MAX at bionic/libc/include/limits.h, but does not ship @@ -127,14 +127,14 @@ bool WeakFileHandleFileWriter::WriteIoVec(std::vector* iovecs) { DCHECK_EQ(remaining_iovecs, 0u); -#else // !OS_POSIX +#else // !BUILDFLAG(IS_POSIX) for (const WritableIoVec& iov : *iovecs) { if (!Write(iov.iov_base, iov.iov_len)) return false; } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) #ifndef NDEBUG // The interface says that |iovecs| is not sacred, so scramble it to make sure @@ -171,7 +171,7 @@ bool FileWriter::Open(const base::FilePath& path, return true; } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) bool FileWriter::OpenMemfd(const base::FilePath& path) { CHECK(!file_.is_valid()); file_.reset(LoggingOpenMemoryFileForReadAndWrite(path)); diff --git a/util/file/file_writer.h b/util/file/file_writer.h index 4ba7a43868..8d82d1473c 100644 --- a/util/file/file_writer.h +++ b/util/file/file_writer.h @@ -20,6 +20,7 @@ #include #include "base/files/file_path.h" +#include "build/build_config.h" #include "util/file/file_io.h" #include "util/file/file_seeker.h" @@ -136,7 +137,7 @@ class FileWriter : public FileWriterInterface { FileWriteMode write_mode, FilePermissions permissions); -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) //! \brief Wraps LoggingOpenMemoryFileForWrite(). //! //! \return `true` if the operation succeeded, `false` if it failed, with an diff --git a/util/file/filesystem_posix.cc b/util/file/filesystem_posix.cc index c413397447..8853b9f67e 100644 --- a/util/file/filesystem_posix.cc +++ b/util/file/filesystem_posix.cc @@ -33,9 +33,9 @@ bool FileModificationTime(const base::FilePath& path, timespec* mtime) { return false; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) *mtime = st.st_mtimespec; -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) // This is needed to compile with traditional NDK headers. mtime->tv_sec = st.st_mtime; mtime->tv_nsec = st.st_mtime_nsec; diff --git a/util/file/filesystem_test.cc b/util/file/filesystem_test.cc index 9338cdcc12..cc683b3a07 100644 --- a/util/file/filesystem_test.cc +++ b/util/file/filesystem_test.cc @@ -31,7 +31,7 @@ namespace { constexpr char kTestFileContent[] = "file_content"; bool CurrentTime(timespec* now) { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) timeval now_tv; int res = gettimeofday(&now_tv, nullptr); if (res != 0) { @@ -40,7 +40,7 @@ bool CurrentTime(timespec* now) { } TimevalToTimespec(now_tv, now); return true; -#elif defined(OS_POSIX) +#elif BUILDFLAG(IS_POSIX) int res = clock_gettime(CLOCK_REALTIME, now); if (res != 0) { EXPECT_EQ(res, 0) << ErrnoMessage("clock_gettime"); @@ -90,7 +90,7 @@ TEST(Filesystem, FileModificationTime) { temp_dir.path().Append(FILE_PATH_LITERAL("notafile")), &mtime)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, FileModificationTime_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -140,7 +140,7 @@ TEST(Filesystem, FileModificationTime_SymbolicLinks) { EXPECT_LE(mtime.tv_sec, expected_time_end.tv_sec + 2); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, CreateDirectory) { ScopedTempDir temp_dir; @@ -221,7 +221,7 @@ TEST(Filesystem, MoveFileOrDirectory) { EXPECT_TRUE(IsRegularFile(file)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -284,7 +284,7 @@ TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) { EXPECT_FALSE(PathExists(link2)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, IsRegularFile) { EXPECT_FALSE(IsRegularFile(base::FilePath())); @@ -299,7 +299,7 @@ TEST(Filesystem, IsRegularFile) { EXPECT_TRUE(IsRegularFile(file)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, IsRegularFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -323,7 +323,7 @@ TEST(Filesystem, IsRegularFile_SymbolicLinks) { EXPECT_FALSE(IsRegularFile(dir_link)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, IsDirectory) { EXPECT_FALSE(IsDirectory(base::FilePath(), false)); @@ -341,7 +341,7 @@ TEST(Filesystem, IsDirectory) { EXPECT_FALSE(IsDirectory(file, true)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, IsDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -368,7 +368,7 @@ TEST(Filesystem, IsDirectory_SymbolicLinks) { EXPECT_TRUE(IsDirectory(dir_link, true)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, RemoveFile) { EXPECT_FALSE(LoggingRemoveFile(base::FilePath())); @@ -390,7 +390,7 @@ TEST(Filesystem, RemoveFile) { EXPECT_FALSE(LoggingRemoveFile(file)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, RemoveFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -417,7 +417,7 @@ TEST(Filesystem, RemoveFile_SymbolicLinks) { EXPECT_TRUE(PathExists(dir)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, RemoveDirectory) { EXPECT_FALSE(LoggingRemoveDirectory(base::FilePath())); @@ -432,7 +432,7 @@ TEST(Filesystem, RemoveDirectory) { EXPECT_FALSE(LoggingRemoveDirectory(file)); ASSERT_TRUE(CreateFile(file)); -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) // The current implementation of Fuchsia's rmdir() simply calls unlink(), and // unlink() works on all FS objects. This is incorrect as // http://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html says @@ -447,7 +447,7 @@ TEST(Filesystem, RemoveDirectory) { EXPECT_TRUE(LoggingRemoveDirectory(dir)); } -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, RemoveDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { @@ -472,7 +472,7 @@ TEST(Filesystem, RemoveDirectory_SymbolicLinks) { EXPECT_TRUE(LoggingRemoveFile(link)); } -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) TEST(Filesystem, GetFileSize) { ScopedTempDir temp_dir; @@ -486,13 +486,13 @@ TEST(Filesystem, GetFileSize) { uint64_t filesize = GetFileSize(filepath); EXPECT_EQ(filesize, sizeof(kTestFileContent)); -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) // Create a link to a file. base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link"))); ASSERT_TRUE(CreateSymbolicLink(filepath, link)); uint64_t filesize_link = GetFileSize(link); EXPECT_EQ(filesize_link, 0u); -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) } TEST(Filesystem, GetDirectorySize) { @@ -516,7 +516,7 @@ TEST(Filesystem, GetDirectorySize) { writer2.Write(kTestFileContent, sizeof(kTestFileContent)); writer2.Close(); -#if !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_FUCHSIA) // Create a link to a file. base::FilePath link(dir.Append(FILE_PATH_LITERAL("link"))); ASSERT_TRUE(CreateSymbolicLink(filepath2, link)); @@ -524,7 +524,7 @@ TEST(Filesystem, GetDirectorySize) { // Create a link to a dir. base::FilePath linkdir(temp_dir.path().Append(FILE_PATH_LITERAL("link"))); ASSERT_TRUE(CreateSymbolicLink(dir, linkdir)); -#endif // !OS_FUCHSIA +#endif // !BUILDFLAG(IS_FUCHSIA) uint64_t filesize = GetDirectorySize(temp_dir.path()); EXPECT_EQ(filesize, 2 * sizeof(kTestFileContent)); diff --git a/util/linux/auxiliary_vector_test.cc b/util/linux/auxiliary_vector_test.cc index 75c20d1a09..a230de6f1a 100644 --- a/util/linux/auxiliary_vector_test.cc +++ b/util/linux/auxiliary_vector_test.cc @@ -33,7 +33,7 @@ #include "util/numeric/int128.h" #include "util/process/process_memory_linux.h" -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) // TODO(jperaza): This symbol isn't defined when building in chromium for // Android. There may be another symbol to use. extern "C" { @@ -72,7 +72,7 @@ void TestAgainstCloneOrSelf(pid_t pid) { ASSERT_TRUE(aux.GetValue(AT_BASE, &interp_base)); EXPECT_TRUE(mappings.FindMapping(interp_base)); -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) LinuxVMAddress entry_addr; ASSERT_TRUE(aux.GetValue(AT_ENTRY, &entry_addr)); EXPECT_EQ(entry_addr, FromPointerCast(START_SYMBOL)); diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index 608a199c0d..ed1c9fbb25 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -30,7 +30,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc index 27f180c6e1..a5530f738d 100644 --- a/util/linux/exception_handler_protocol.cc +++ b/util/linux/exception_handler_protocol.cc @@ -14,15 +14,19 @@ #include "util/linux/exception_handler_protocol.h" +#include "build/build_config.h" + namespace crashpad { ExceptionHandlerProtocol::ClientInformation::ClientInformation() : exception_information_address(0), sanitization_information_address(0) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) - , crash_loop_before_time(0) -#endif // OS_LINUX || OS_CHROMEOS -{} +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) + , + crash_loop_before_time(0) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +{ +} ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage() : version(kVersion), diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index cbd24418a6..6a38acd54f 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -51,7 +51,7 @@ class ExceptionHandlerProtocol { //! SanitizationInformation struct, or 0 if there is no such struct. VMAddress sanitization_information_address; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) //! \brief Indicates that the client is likely in a crash loop if a crash //! occurs before this timestamp. This value is only used by ChromeOS's //! `/sbin/crash_reporter`. diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 47eec973f2..3e845c4c6f 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -398,7 +398,7 @@ std::unique_ptr MemoryMap::FindFilePossibleMmapStarts( return std::make_unique(); } -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) // The Android Chromium linker uses ashmem to share RELRO segments between // processes. The original RELRO segment has been unmapped and replaced with a // mapping named "/dev/ashmem/RELRO:" where is the base @@ -427,17 +427,17 @@ std::unique_ptr MemoryMap::FindFilePossibleMmapStarts( } } } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) for (const auto& candidate : mappings_) { if (candidate.device == mapping.device && candidate.inode == mapping.inode -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) // Libraries on Android may be mapped from zipfiles (APKs), in which // case the offset is not 0. && candidate.offset == 0 -#endif // !defined(OS_ANDROID) - ) { +#endif // !BUILDFLAG(IS_ANDROID) + ) { possible_starts.push_back(&candidate); } if (mapping.Equals(candidate)) { diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index 4ab7b05c43..d77dd0da5d 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -101,7 +101,7 @@ TEST(MemoryMap, SelfBasic) { ASSERT_TRUE(mapping); EXPECT_GE(code_address, mapping->range.Base()); EXPECT_LT(code_address, mapping->range.End()); -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) // Android Q+ supports execute only memory. EXPECT_TRUE(mapping->readable); #endif @@ -174,7 +174,7 @@ class MapChildTest : public Multiprocess { ASSERT_TRUE(mapping); EXPECT_GE(code_address, mapping->range.Base()); EXPECT_LT(code_address, mapping->range.End()); -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) // Android Q+ supports execute only memory. EXPECT_TRUE(mapping->readable); #endif @@ -426,7 +426,7 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start, EXPECT_EQ(mappings->Next(), mapping2); mappings = map.FindFilePossibleMmapStarts(*mapping3); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(mappings->Count(), 2u); #else ASSERT_EQ(mappings->Count(), 1u); @@ -474,7 +474,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) { ASSERT_NE(mapping1, mapping2); ASSERT_NE(mapping2, mapping3); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) auto mappings = map.FindFilePossibleMmapStarts(*mapping1); EXPECT_EQ(mappings->Count(), 1u); EXPECT_EQ(mappings->Next(), mapping1); @@ -622,7 +622,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { auto mapping = map.FindMapping(file_mapping0.addr_as()); ASSERT_TRUE(mapping); auto possible_starts = map.FindFilePossibleMmapStarts(*mapping); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(possible_starts->Count(), 1u); #else EXPECT_EQ(possible_starts->Count(), 0u); @@ -631,7 +631,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { mapping = map.FindMapping(file_mapping1.addr_as()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(possible_starts->Count(), 2u); #else EXPECT_EQ(possible_starts->Count(), 1u); @@ -640,7 +640,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { mapping = map.FindMapping(file_mapping2.addr_as()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(possible_starts->Count(), 3u); #else EXPECT_EQ(possible_starts->Count(), 2u); @@ -649,7 +649,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { mapping = map.FindMapping(file_mapping3.addr_as()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(possible_starts->Count(), 4u); #else EXPECT_EQ(possible_starts->Count(), 3u); @@ -658,7 +658,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { mapping = map.FindMapping(file_mapping4.addr_as()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) EXPECT_EQ(possible_starts->Count(), 5u); #else EXPECT_EQ(possible_starts->Count(), 4u); diff --git a/util/linux/thread_info.h b/util/linux/thread_info.h index 5b55c24a76..d3f3b2c695 100644 --- a/util/linux/thread_info.h +++ b/util/linux/thread_info.h @@ -24,7 +24,7 @@ #include "util/linux/address_types.h" #include "util/numeric/int128.h" -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) #include #endif @@ -261,11 +261,12 @@ union FloatContext { // __ANDROID_API_N__ is a proxy for determining whether unified headers are in // use. It’s only defined by unified headers. Unified headers call this // structure user_fpxregs_struct regardless of API level. -#if defined(OS_ANDROID) && __ANDROID_API__ <= 19 && !defined(__ANDROID_API_N__) +#if BUILDFLAG(IS_ANDROID) && __ANDROID_API__ <= 19 && \ + !defined(__ANDROID_API_N__) using NativeFpxregs = user_fxsr_struct; #else using NativeFpxregs = user_fpxregs_struct; -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) static_assert(sizeof(f32_t::fxsave) == sizeof(NativeFpxregs), "Size mismatch"); #elif defined(ARCH_CPU_X86_64) diff --git a/util/mach/exc_server_variants.cc b/util/mach/exc_server_variants.cc index b9357a7802..9d36f3b0a2 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -686,10 +686,10 @@ kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception, exception_behavior_t behavior, bool set_thread_state) { if (exception == EXC_CRASH -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11 +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11 && MacOSVersionNumber() >= 10'11'00 #endif - ) { + ) { return KERN_SUCCESS; } diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index d74cbc5915..f5be0ea04b 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -31,9 +31,9 @@ #include "util/mach/mach_message.h" #include "util/misc/implicit_cast.h" -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) #include "test/mac/mach_multiprocess.h" -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) namespace crashpad { namespace test { @@ -962,7 +962,7 @@ TEST(ExcServerVariants, MachMessageServerRequestIDs) { expect_request_ids); } -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) class TestExcServerVariants : public MachMultiprocess, public UniversalMachExcServer::Interface { @@ -1203,10 +1203,10 @@ TEST(ExcServerVariants, ThreadStates) { } } -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // iOS 9 ≅ OS X 10.11. const kern_return_t prefer_not_set_thread_state = KERN_SUCCESS; #else diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index 7f80693888..dcff5c2a89 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -44,12 +44,12 @@ exception_mask_t ExcMaskAll() { // 10.9.4 xnu-2422.110.17/osfmk/mach/ipc_host.c and // xnu-2422.110.17/osfmk/mach/ipc_tt.c. -#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 +#if BUILDFLAG(IS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 // iOS 7 ≅ OS X 10.9. #error This code was not ported to iOS versions older than 7 #endif -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 const int macos_version_number = MacOSVersionNumber(); #endif @@ -66,7 +66,7 @@ exception_mask_t ExcMaskAll() { EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | EXC_MASK_MACHINE; -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8 +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8 if (macos_version_number < 10'08'00) { return kExcMaskAll_10_6; } @@ -76,7 +76,7 @@ exception_mask_t ExcMaskAll() { // xnu-2050.48.11/osfmk/mach/exception_types.h. constexpr exception_mask_t kExcMaskAll_10_8 = kExcMaskAll_10_6 | EXC_MASK_RESOURCE; -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 if (macos_version_number < 10'09'00) { return kExcMaskAll_10_8; } @@ -91,12 +91,12 @@ exception_mask_t ExcMaskAll() { exception_mask_t ExcMaskValid() { const exception_mask_t kExcMaskValid_10_6 = ExcMaskAll() | EXC_MASK_CRASH; -#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 +#if BUILDFLAG(IS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 // iOS 9 ≅ OS X 10.11. #error This code was not ported to iOS versions older than 9 #endif -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11 +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11 if (MacOSVersionNumber() < 10'11'00) { return kExcMaskValid_10_6; } diff --git a/util/mach/mach_extensions_test.cc b/util/mach/mach_extensions_test.cc index 4ff53d9422..57e03ad153 100644 --- a/util/mach/mach_extensions_test.cc +++ b/util/mach/mach_extensions_test.cc @@ -80,11 +80,11 @@ TEST(MachExtensions, ExcMaskAll) { EXPECT_FALSE(exc_mask_all & EXC_MASK_CRASH); EXPECT_FALSE(exc_mask_all & EXC_MASK_CORPSE_NOTIFY); -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // Assume at least iOS 7 (≅ OS X 10.9). EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD); -#else // OS_IOS +#else // BUILDFLAG(IS_IOS) const int macos_version_number = MacOSVersionNumber(); if (macos_version_number >= 10'08'00) { EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); @@ -97,7 +97,7 @@ TEST(MachExtensions, ExcMaskAll) { } else { EXPECT_FALSE(exc_mask_all & EXC_MASK_GUARD); } -#endif // OS_IOS +#endif // BUILDFLAG(IS_IOS) // Bit 0 should not be set. EXPECT_FALSE(ExcMaskAll() & 1); @@ -112,12 +112,12 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_CRASH); -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // Assume at least iOS 9 (≅ OS X 10.11). EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE); EXPECT_TRUE(exc_mask_valid & EXC_MASK_GUARD); EXPECT_TRUE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY); -#else // OS_IOS +#else // BUILDFLAG(IS_IOS) const int macos_version_number = MacOSVersionNumber(); if (macos_version_number >= 10'08'00) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE); @@ -136,7 +136,7 @@ TEST(MachExtensions, ExcMaskValid) { } else { EXPECT_FALSE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY); } -#endif // OS_IOS +#endif // BUILDFLAG(IS_IOS) // Bit 0 should not be set. EXPECT_FALSE(ExcMaskValid() & 1); diff --git a/util/mach/mach_message.cc b/util/mach/mach_message.cc index 00fe116f88..ac76a53864 100644 --- a/util/mach/mach_message.cc +++ b/util/mach/mach_message.cc @@ -20,12 +20,13 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" +#include "build/build_config.h" #include "util/misc/clock.h" #include "util/misc/implicit_cast.h" -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) #include -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) namespace crashpad { @@ -253,7 +254,7 @@ bool MachMessageDestroyReceivedPort(mach_port_t port, } } -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) { if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) { @@ -287,6 +288,6 @@ pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) { return audit_pid; } -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) } // namespace crashpad diff --git a/util/mach/mach_message.h b/util/mach/mach_message.h index c58b6d05fa..e670a13e7d 100644 --- a/util/mach/mach_message.h +++ b/util/mach/mach_message.h @@ -183,7 +183,7 @@ const mach_msg_trailer_t* MachMessageTrailerFromHeader( bool MachMessageDestroyReceivedPort(mach_port_t port, mach_msg_type_name_t port_right_type); -#if defined(OS_MAC) || DOXYGEN +#if BUILDFLAG(IS_MAC) || DOXYGEN //! \brief Returns the process ID of a Mach message’s sender from its audit //! trailer. @@ -201,7 +201,7 @@ bool MachMessageDestroyReceivedPort(mach_port_t port, //! audit information. pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer); -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) } // namespace crashpad diff --git a/util/mach/mach_message_test.cc b/util/mach/mach_message_test.cc index 0c578b92d7..587061ff71 100644 --- a/util/mach/mach_message_test.cc +++ b/util/mach/mach_message_test.cc @@ -19,6 +19,7 @@ #include #include "base/mac/scoped_mach_port.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "util/mach/mach_extensions.h" @@ -159,7 +160,7 @@ TEST(MachMessage, MachMessageDestroyReceivedPort) { EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND)); } -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) TEST(MachMessage, AuditPIDFromMachMessageTrailer) { base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); @@ -201,7 +202,7 @@ TEST(MachMessage, AuditPIDFromMachMessageTrailer) { EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid()); } -#endif // OS_MAC +#endif // BUILDFLAG(IS_MAC) } // namespace } // namespace test diff --git a/util/misc/address_types.h b/util/misc/address_types.h index 14942bd8ea..8902efb6cd 100644 --- a/util/misc/address_types.h +++ b/util/misc/address_types.h @@ -21,13 +21,13 @@ #include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include "util/win/address_types.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/linux/address_types.h" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include #else #error "Unhandled OS type" @@ -45,22 +45,22 @@ using VMAddress = uint64_t; //! VMAddress), potentially across bitness. using VMSize = uint64_t; -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) using VMAddress = mach_vm_address_t; using VMSize = mach_vm_size_t; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using VMAddress = WinVMAddress; using VMSize = WinVMSize; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) using VMAddress = LinuxVMAddress; using VMSize = LinuxVMSize; -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) using VMAddress = zx_vaddr_t; using VMSize = size_t; diff --git a/util/misc/capture_context.h b/util/misc/capture_context.h index d21a24f19f..37ed40021d 100644 --- a/util/misc/capture_context.h +++ b/util/misc/capture_context.h @@ -17,30 +17,30 @@ #include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #if defined(ARCH_CPU_X86_FAMILY) using NativeCPUContext = x86_thread_state; #elif defined(ARCH_CPU_ARM64) using NativeCPUContext = arm_unified_thread_state; #endif -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using NativeCPUContext = CONTEXT; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \ - defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) using NativeCPUContext = ucontext_t; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) //! \brief Saves the CPU context. //! diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index cf23c2deff..a24ea15045 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -28,14 +28,14 @@ namespace crashpad { namespace test { namespace { -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) // Fuchsia uses -fsanitize=safe-stack by default, which splits local variables // and the call stack into separate regions (see // https://clang.llvm.org/docs/SafeStack.html). Because this test would like to // find an approximately valid stack pointer by comparing locals to the // captured one, disable safe-stack for this function. __attribute__((no_sanitize("safe-stack"))) -#endif // defined(OS_FUCHSIA) +#endif // BUILDFLAG(IS_FUCHSIA) #if defined(MEMORY_SANITIZER) // CaptureContext() calls inline assembly and is incompatible with MSan. diff --git a/util/misc/clock_posix.cc b/util/misc/clock_posix.cc index a9fe8e5856..448f843102 100644 --- a/util/misc/clock_posix.cc +++ b/util/misc/clock_posix.cc @@ -30,7 +30,7 @@ constexpr uint64_t kNanosecondsPerSecond = 1E9; namespace crashpad { -#if !defined(OS_APPLE) +#if !BUILDFLAG(IS_APPLE) uint64_t ClockMonotonicNanoseconds() { timespec now; diff --git a/util/misc/clock_test.cc b/util/misc/clock_test.cc index 443d496b05..a1b1a4fa4e 100644 --- a/util/misc/clock_test.cc +++ b/util/misc/clock_test.cc @@ -21,6 +21,7 @@ #include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad { @@ -41,17 +42,17 @@ TEST(Clock, ClockMonotonicNanoseconds) { EXPECT_GE(now, last); } -#if !defined(OS_WIN) // No SleepNanoseconds implemented on Windows. +#if !BUILDFLAG(IS_WIN) // No SleepNanoseconds implemented on Windows. // SleepNanoseconds() should sleep for at least the value of the clock’s // resolution, so the clock’s value should definitely increase after a sleep. // EXPECT_GT can be used instead of EXPECT_GE after the sleep. SleepNanoseconds(1); now = ClockMonotonicNanoseconds(); EXPECT_GT(now, start); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } -#if !defined(OS_WIN) // No SleepNanoseconds implemented on Windows. +#if !BUILDFLAG(IS_WIN) // No SleepNanoseconds implemented on Windows. void TestSleepNanoseconds(uint64_t nanoseconds) { uint64_t start = ClockMonotonicNanoseconds(); @@ -91,7 +92,7 @@ TEST(Clock, SleepNanoseconds) { } } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace } // namespace test diff --git a/util/misc/metrics.cc b/util/misc/metrics.cc index 47c9f26f31..2e8459c71d 100644 --- a/util/misc/metrics.cc +++ b/util/misc/metrics.cc @@ -19,15 +19,15 @@ #include "base/numerics/safe_conversions.h" #include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #define METRICS_OS_NAME "Mac" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #define METRICS_OS_NAME "Win" -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) #define METRICS_OS_NAME "Android" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #define METRICS_OS_NAME "Linux" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #define METRICS_OS_NAME "Fuchsia" #endif @@ -115,7 +115,7 @@ void Metrics::HandlerCrashed(uint32_t exception_code) { "Crashpad.HandlerCrash.ExceptionCode." METRICS_OS_NAME, exception_code); } -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) // static void Metrics::MissingIntermediateDumpKey( const internal::IntermediateDumpKey& key) { diff --git a/util/misc/metrics.h b/util/misc/metrics.h index dcd37a6aaa..c870b3a22a 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -20,7 +20,7 @@ #include "build/build_config.h" #include "util/file/file_io.h" -#if defined(OS_IOS) +#if BUILDFLAG(IS_IOS) #include "util/ios/ios_intermediate_dump_format.h" #endif @@ -207,7 +207,7 @@ class Metrics { //! This is currently only reported on Windows. static void HandlerCrashed(uint32_t exception_code); -#if defined(OS_IOS) || DOXYGEN +#if BUILDFLAG(IS_IOS) || DOXYGEN //! \brief Records a missing key from an intermediate dump. static void MissingIntermediateDumpKey( const internal::IntermediateDumpKey& key); diff --git a/util/misc/no_cfi_icall.h b/util/misc/no_cfi_icall.h index 80e584ebd5..1a5ddc68a7 100644 --- a/util/misc/no_cfi_icall.h +++ b/util/misc/no_cfi_icall.h @@ -20,9 +20,9 @@ #include "build/build_config.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) namespace crashpad { @@ -39,7 +39,7 @@ namespace { #endif // DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks. -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Windows also needs __declspec(guard(nocf)). #define DISABLE_CFI_ICALL NO_SANITIZE("cfi-icall") __declspec(guard(nocf)) #else @@ -65,7 +65,7 @@ struct FunctorTraits { } }; -#if defined(OS_WIN) && defined(ARCH_CPU_X86) +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86) template struct FunctorTraits { template @@ -74,7 +74,7 @@ struct FunctorTraits { return function(std::forward(args)...); } }; -#endif // OS_WIN && ARCH_CPU_X86 +#endif // BUILDFLAG(IS_WIN) && ARCH_CPU_X86 #if __cplusplus >= 201703L // These specializations match functions which are not explicitly declared @@ -97,7 +97,7 @@ struct FunctorTraits { } }; -#if defined(OS_WIN) && defined(ARCH_CPU_X86) +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86) template struct FunctorTraits { template @@ -106,7 +106,7 @@ struct FunctorTraits { return function(std::forward(args)...); } }; -#endif // OS_WIN && ARCH_CPU_X86 +#endif // BUILDFLAG(IS_WIN) && ARCH_CPU_X86 #endif // __cplusplus >= 201703L @@ -146,14 +146,14 @@ class NoCfiIcall { explicit NoCfiIcall(PointerType function) : function_(reinterpret_cast(function)) {} -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) //! \see NoCfiIcall template ::type, FARPROC>::value>> explicit NoCfiIcall(FARPROC function) : function_(reinterpret_cast(function)) {} -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) ~NoCfiIcall() = default; diff --git a/util/misc/no_cfi_icall_test.cc b/util/misc/no_cfi_icall_test.cc index 5654a2f4a4..56a2cacfda 100644 --- a/util/misc/no_cfi_icall_test.cc +++ b/util/misc/no_cfi_icall_test.cc @@ -19,7 +19,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #include "util/win/get_function.h" @@ -49,7 +49,7 @@ TEST(NoCfiIcall, SameDSOICall) { } TEST(NoCfiIcall, CrossDSOICall) { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) static const NoCfiIcall call( GET_FUNCTION_REQUIRED(L"kernel32.dll", GetCurrentProcessId)); ASSERT_TRUE(call); @@ -62,7 +62,7 @@ TEST(NoCfiIcall, CrossDSOICall) { } TEST(NoCfiIcall, Args) { -#if !defined(OS_WIN) +#if !BUILDFLAG(IS_WIN) static const NoCfiIcall call( dlsym(RTLD_NEXT, "snprintf")); ASSERT_TRUE(call); diff --git a/util/misc/time.h b/util/misc/time.h index dc992bdcce..d695f77d28 100644 --- a/util/misc/time.h +++ b/util/misc/time.h @@ -21,7 +21,7 @@ #include "build/build_config.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #endif @@ -45,7 +45,7 @@ bool TimespecToTimeval(const timespec& ts, timeval* tv); //! \brief Convert the timeval \a tv to a timespec \a ts. void TimevalToTimespec(const timeval& tv, timespec* ts); -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief Convert a `timespec` to a Windows `FILETIME`, converting from POSIX //! epoch to Windows epoch. @@ -67,15 +67,17 @@ timeval FiletimeToTimevalInterval(const FILETIME& filetime); //! UTC. void GetTimeOfDay(timeval* tv); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || DOXYGEN +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \ + DOXYGEN //! \brief Get the kernel boot time. Subsequent calls to this function may //! return different results due to the system clock being changed or //! imprecision in measuring the boot time. //! \return `true` on success. Otherwise, `false` with a message logged. bool GetBootTime(timespec* ts); -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID || DOXYGEN +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) || DOXYGEN } // namespace crashpad diff --git a/util/misc/time_test.cc b/util/misc/time_test.cc index 87e28faae3..d3ae956639 100644 --- a/util/misc/time_test.cc +++ b/util/misc/time_test.cc @@ -16,6 +16,7 @@ #include +#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad { @@ -71,7 +72,7 @@ TEST(Time, TimeConversions) { EXPECT_TRUE(TimespecToTimeval(kEndOfTime, &end_of_timeval)); } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) constexpr uint64_t kBirthdateFiletimeIntervals = 130512285140000324; FILETIME filetime_birthdate; filetime_birthdate.dwLowDateTime = 0xffffffff & kBirthdateFiletimeIntervals; @@ -112,10 +113,10 @@ TEST(Time, TimeConversions) { elapsed_timeval = FiletimeToTimevalInterval(elapsed_filetime); EXPECT_EQ(elapsed_timeval.tv_sec, 429); EXPECT_EQ(elapsed_timeval.tv_usec, 496729); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) TEST(Time, GetTimeOfDay) { timeval t; @@ -125,7 +126,7 @@ TEST(Time, GetTimeOfDay) { EXPECT_LT(approx_now - 100, t.tv_sec); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace } // namespace test diff --git a/util/misc/uuid.cc b/util/misc/uuid.cc index 4ed3831175..6ad7e67277 100644 --- a/util/misc/uuid.cc +++ b/util/misc/uuid.cc @@ -29,10 +29,11 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/sys_byteorder.h" +#include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { @@ -87,20 +88,20 @@ bool UUID::InitializeFromString(const base::StringPiece& string) { return true; } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) bool UUID::InitializeFromString(const base::WStringPiece& string) { return InitializeFromString(WideToUTF8(string)); } #endif bool UUID::InitializeWithNew() { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) uuid_t uuid; uuid_generate(uuid); InitializeFromBytes(uuid); return true; -#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ - defined(OS_ANDROID) || defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA) // Linux, Android, and Fuchsia do not provide a UUID generator in a // widely-available system library. On Linux and Android, uuid_generate() // from libuuid is not available everywhere. @@ -115,10 +116,10 @@ bool UUID::InitializeWithNew() { return true; #else #error Port. -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) void UUID::InitializeFromSystemUUID(const ::UUID* system_uuid) { static_assert(sizeof(::UUID) == sizeof(UUID), "unexpected system uuid size"); @@ -126,7 +127,7 @@ void UUID::InitializeFromSystemUUID(const ::UUID* system_uuid) { "unexpected system uuid layout"); memcpy(this, system_uuid, sizeof(*this)); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) std::string UUID::ToString() const { return base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", @@ -143,10 +144,10 @@ std::string UUID::ToString() const { data_5[5]); } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) std::wstring UUID::ToWString() const { return base::UTF8ToWide(ToString()); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace crashpad diff --git a/util/misc/uuid.h b/util/misc/uuid.h index 7e504a2253..574f01dc20 100644 --- a/util/misc/uuid.h +++ b/util/misc/uuid.h @@ -22,7 +22,7 @@ #include "base/strings/string_piece.h" #include "build/build_config.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #endif @@ -63,9 +63,9 @@ struct UUID { //! been initialized with the data. `false` if the string could not be //! parsed, with the object state untouched. bool InitializeFromString(const base::StringPiece& string); -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN bool InitializeFromString(const base::WStringPiece& string); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) //! \brief Initializes the %UUID using a standard system facility to generate //! the value. @@ -74,22 +74,22 @@ struct UUID { //! with a message logged. bool InitializeWithNew(); -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief Initializes the %UUID from a system `UUID` or `GUID` structure. //! //! \param[in] system_uuid A system `UUID` or `GUID` structure. void InitializeFromSystemUUID(const ::UUID* system_uuid); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) //! \brief Formats the %UUID per RFC 4122 §3. //! //! \return A string of the form `"00112233-4455-6677-8899-aabbccddeeff"`. std::string ToString() const; -#if defined(OS_WIN) || DOXYGEN +#if BUILDFLAG(IS_WIN) || DOXYGEN //! \brief The same as ToString, but returned as a wstring. std::wstring ToWString() const; -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) // These fields are laid out according to RFC 4122 §4.1.2. uint32_t data_1; diff --git a/util/misc/uuid_test.cc b/util/misc/uuid_test.cc index 28d7ce4bd6..aea126ab56 100644 --- a/util/misc/uuid_test.cc +++ b/util/misc/uuid_test.cc @@ -23,6 +23,7 @@ #include "base/format_macros.h" #include "base/scoped_generic.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad { @@ -231,7 +232,7 @@ TEST(UUID, FromString) { uuid.InitializeFromString("5762C15D-50b5-4171-a2e9-7429C9EC6CAB"); EXPECT_EQ(uuid.ToString(), "5762c15d-50b5-4171-a2e9-7429c9ec6cab"); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Test accepting a StringPiece16 via L"" literals on Windows. EXPECT_TRUE( uuid.InitializeFromString(L"F32E5BDC-2681-4C73-A4E6-444FFD44B444")); @@ -240,10 +241,10 @@ TEST(UUID, FromString) { EXPECT_TRUE( uuid.InitializeFromString(L"5762C15D-50b5-4171-a2e9-5555C5EC5CAB")); EXPECT_EQ(uuid.ToString(), "5762c15d-50b5-4171-a2e9-5555c5ec5cab"); -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) TEST(UUID, FromSystem) { ::GUID system_uuid; @@ -268,7 +269,7 @@ TEST(UUID, FromSystem) { EXPECT_EQ(uuid.ToWString(), reinterpret_cast(system_string)); } -#endif // OS_WIN +#endif // BUILDFLAG(IS_WIN) } // namespace } // namespace test diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index 4de9280325..286c2ab082 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -27,6 +27,7 @@ #include "base/scoped_generic.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "util/file/file_io.h" #include "util/net/http_body.h" #include "util/net/url.h" @@ -127,13 +128,13 @@ class SSLStream : public Stream { return false; } } else { -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) if (SSL_CTX_load_verify_locations( ctx_.get(), nullptr, "/etc/ssl/certs") <= 0) { LOG(ERROR) << "SSL_CTX_load_verify_locations"; return false; } -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) if (SSL_CTX_load_verify_locations( ctx_.get(), "/config/ssl/cert.pem", nullptr) <= 0) { LOG(ERROR) << "SSL_CTX_load_verify_locations"; diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index cf53450ee4..6c13bfad0f 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -41,7 +41,7 @@ namespace crashpad { namespace test { namespace { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) std::string ToUTF8IfWin(const std::wstring& x) { return base::WideToUTF8(x); } @@ -70,7 +70,7 @@ class HTTPTransportTestFixture : public MultiprocessExec { scheme_and_host_() { base::FilePath server_path = TestPaths::Executable().DirName().Append( FILE_PATH_LITERAL("http_transport_test_server") -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) FILE_PATH_LITERAL(".exe") #endif ); @@ -361,7 +361,7 @@ TEST_P(HTTPTransport, Upload33k_LengthUnknown) { } // This should be on for Fuchsia, but DX-382. Debug and re-enabled. -#if defined(CRASHPAD_USE_BORINGSSL) && !defined(OS_FUCHSIA) +#if defined(CRASHPAD_USE_BORINGSSL) && !BUILDFLAG(IS_FUCHSIA) // The test server requires BoringSSL or OpenSSL, so https in tests can only be // enabled where that's readily available. Additionally on Linux, the bots fail // lacking libcrypto.so.1.1, so disabled there for now. On Mac, they could also diff --git a/util/net/http_transport_test_server.cc b/util/net/http_transport_test_server.cc index a3bcc6a5ab..4e30cbdc86 100644 --- a/util/net/http_transport_test_server.cc +++ b/util/net/http_transport_test_server.cc @@ -122,13 +122,13 @@ int HttpTransportTestServerMain(int argc, char* argv[]) { } // namespace } // namespace crashpad -#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) int main(int argc, char* argv[]) { return crashpad::HttpTransportTestServerMain(argc, argv); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) int wmain(int argc, wchar_t* argv[]) { return crashpad::ToolSupport::Wmain( argc, argv, crashpad::HttpTransportTestServerMain); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) diff --git a/util/numeric/checked_address_range.cc b/util/numeric/checked_address_range.cc index 4ba7ff3900..1f5abc27e9 100644 --- a/util/numeric/checked_address_range.cc +++ b/util/numeric/checked_address_range.cc @@ -17,16 +17,17 @@ #include "base/check_op.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include "util/win/address_types.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/linux/address_types.h" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) namespace crashpad { namespace internal { @@ -126,15 +127,15 @@ std::string CheckedAddressRangeGeneric::AsString() const { } // Explicit instantiations for the cases we use. -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) template class CheckedAddressRangeGeneric; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) template class CheckedAddressRangeGeneric; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) template class CheckedAddressRangeGeneric; -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) template class CheckedAddressRangeGeneric; -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) } // namespace internal } // namespace crashpad diff --git a/util/posix/close_multiple.cc b/util/posix/close_multiple.cc index 2e0ad1056e..ec15e06fff 100644 --- a/util/posix/close_multiple.cc +++ b/util/posix/close_multiple.cc @@ -31,7 +31,7 @@ #include "util/file/directory_reader.h" #include "util/misc/implicit_cast.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include #endif @@ -51,7 +51,7 @@ namespace { void CloseNowOrOnExec(int fd, bool ebadf_ok) { int rv; -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // Try to set close-on-exec, to avoid attempting to close a guarded FD with // a close guard set. rv = fcntl(fd, F_SETFD, FD_CLOEXEC); @@ -72,9 +72,9 @@ void CloseNowOrOnExec(int fd, bool ebadf_ok) { // This is an advantage over looping over all possible file descriptors, because // no attempt needs to be made to close file descriptors that are not open. bool CloseMultipleNowOrOnExecUsingFDDir(int min_fd, int preserve_fd) { -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) static constexpr char kFDDir[] = "/dev/fd"; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) static constexpr char kFDDir[] = "/proc/self/fd"; #endif @@ -128,14 +128,15 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { // bionic/libc/bionic/ndk_cruft.cpp getdtablesize(). int max_fd = implicit_cast(sysconf(_SC_OPEN_MAX)); -#if !defined(OS_ANDROID) +#if !BUILDFLAG(IS_ANDROID) // getdtablesize() was removed effective Android 5.0.0 (API 21). Since it // returns the same thing as the sysconf() above, just skip it. See // https://android.googlesource.com/platform/bionic/+/462abab12b074c62c0999859e65d5a32ebb41951. max_fd = std::max(max_fd, getdtablesize()); #endif -#if !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)) || \ +#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \ + BUILDFLAG(IS_ANDROID)) || \ defined(OPEN_MAX) // Linux does not provide OPEN_MAX. See // https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/include/linux/limits.h?id=77293034696e3e0b6c8b8fc1f96be091104b3d2b. @@ -147,7 +148,7 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { // while the system is running, but it’s still a better upper bound than the // current RLIMIT_NOFILE value. -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // See 10.11.6 xnu-3248.60.10/bsd/kern/kern_resource.c maxfilesperproc, // referenced by dosetrlimit(). int oid[] = {CTL_KERN, KERN_MAXFILESPERPROC}; @@ -163,7 +164,7 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { } else { PLOG(WARNING) << "sysctl"; } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // See linux-4.4.27/fs/file.c sysctl_nr_open, referenced by kernel/sys.c // do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is // not considered an error, because /proc may not be available or usable. diff --git a/util/posix/drop_privileges.cc b/util/posix/drop_privileges.cc index 75650d5a68..82aa1eba1d 100644 --- a/util/posix/drop_privileges.cc +++ b/util/posix/drop_privileges.cc @@ -25,7 +25,7 @@ void DropPrivileges() { gid_t gid = getgid(); uid_t uid = getuid(); -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) // Based on the POSIX.1-2008 2013 edition documentation for setreuid() and // setregid(), setreuid() and setregid() alone should be sufficient to drop // privileges. The standard specifies that the saved ID should be set to the @@ -73,7 +73,7 @@ void DropPrivileges() { CHECK_EQ(setegid(egid), -1); } } -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) PCHECK(setresgid(gid, gid, gid) == 0) << "setresgid"; PCHECK(setresuid(uid, uid, uid) == 0) << "setresuid"; diff --git a/util/posix/process_info.h b/util/posix/process_info.h index 7a58788dfa..d3f1c992fc 100644 --- a/util/posix/process_info.h +++ b/util/posix/process_info.h @@ -27,12 +27,12 @@ #include "util/misc/initialization_state.h" #include "util/misc/initialization_state_dcheck.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include #include #endif -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/linux/ptrace_connection.h" #endif @@ -47,7 +47,8 @@ class ProcessInfo { ~ProcessInfo(); -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || DOXYGEN +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \ + DOXYGEN //! \brief Initializes this object with information about the process whose ID //! is \a pid using a PtraceConnection \a connection. //! @@ -62,9 +63,10 @@ class ProcessInfo { //! //! \return `true` on success, `false` on failure with a message logged. bool InitializeWithPtrace(PtraceConnection* connection); -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID || DOXYGEN +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) || DOXYGEN -#if defined(OS_APPLE) || DOXYGEN +#if BUILDFLAG(IS_APPLE) || DOXYGEN //! \brief Initializes this object with information about the process whose ID //! is \a pid. //! @@ -169,9 +171,9 @@ class ProcessInfo { bool Arguments(std::vector* argv) const; private: -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) kinfo_proc kern_proc_info_; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // Some members are marked mutable so that they can be lazily initialized by // const methods. These are always InitializationState-protected so that // multiple successive calls will always produce the same return value and out diff --git a/util/posix/process_info_test.cc b/util/posix/process_info_test.cc index 1d9b065743..8456b72c49 100644 --- a/util/posix/process_info_test.cc +++ b/util/posix/process_info_test.cc @@ -33,7 +33,7 @@ #include "util/misc/implicit_cast.h" #include "util/string/split_string.h" -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/linux/direct_ptrace_connection.h" #include "test/linux/fake_ptrace_connection.h" #endif @@ -98,7 +98,7 @@ void TestProcessSelfOrClone(const ProcessInfo& process_info) { const std::vector& expect_argv = GetMainArguments(); -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Prior to Linux 4.2, the kernel only allowed reading a single page from // /proc//cmdline, causing any further arguments to be truncated. Disable // testing arguments in this case. @@ -124,7 +124,8 @@ void TestProcessSelfOrClone(const ProcessInfo& process_info) { argv_size > static_cast(getpagesize())) { return; } -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) std::vector argv; ASSERT_TRUE(process_info.Arguments(&argv)); @@ -161,18 +162,19 @@ void TestSelfProcess(const ProcessInfo& process_info) { TEST(ProcessInfo, Self) { ProcessInfo process_info; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(getpid())); ASSERT_TRUE(process_info.InitializeWithPtrace(&connection)); #else ASSERT_TRUE(process_info.InitializeWithPid(getpid())); -#endif // OS_LINUX || OS_ANDROID || OS_CHROMEOS +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || + // BUILDFLAG(IS_CHROMEOS) TestSelfProcess(process_info); } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) TEST(ProcessInfo, SelfTask) { ProcessInfo process_info; ASSERT_TRUE(process_info.InitializeWithTask(mach_task_self())); @@ -184,7 +186,7 @@ TEST(ProcessInfo, Pid1) { // PID 1 is expected to be init or the system’s equivalent. This tests reading // information about another process. ProcessInfo process_info; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(1)); ASSERT_TRUE(process_info.InitializeWithPtrace(&connection)); @@ -216,7 +218,7 @@ class ProcessInfoForkedTest : public Multiprocess { void MultiprocessParent() override { const pid_t pid = ChildPID(); -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) DirectPtraceConnection connection; ASSERT_TRUE(connection.Initialize(pid)); @@ -225,7 +227,8 @@ class ProcessInfoForkedTest : public Multiprocess { #else ProcessInfo process_info; ASSERT_TRUE(process_info.InitializeWithPid(pid)); -#endif // OS_LINUX || OS_CHROMEOS || OS_ANDROID +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || + // BUILDFLAG(IS_ANDROID) EXPECT_EQ(process_info.ProcessID(), pid); EXPECT_EQ(process_info.ParentProcessID(), getpid()); diff --git a/util/posix/scoped_mmap.cc b/util/posix/scoped_mmap.cc index 4438393173..1d28581e38 100644 --- a/util/posix/scoped_mmap.cc +++ b/util/posix/scoped_mmap.cc @@ -28,7 +28,7 @@ // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is // complete. -#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "third_party/lss/lss.h" #endif @@ -36,7 +36,7 @@ namespace { // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is // complete. -#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) void* CallMmap(void* addr, size_t len, int prot, diff --git a/util/posix/signals.cc b/util/posix/signals.cc index cd8b87d868..145a4332be 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -21,8 +21,9 @@ #include "base/check_op.h" #include "base/cxx17_backports.h" #include "base/logging.h" +#include "build/build_config.h" -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) #include #endif @@ -50,10 +51,10 @@ constexpr int kCrashSignals[] = { #if defined(SIGEMT) SIGEMT, #endif // defined(SIGEMT) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) SIGXCPU, SIGXFSZ, -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) }; // These are the non-core-generating but terminating signals. @@ -86,13 +87,13 @@ constexpr int kTerminateSignals[] = { #if defined(SIGSTKFLT) SIGSTKFLT, #endif // defined(SIGSTKFLT) -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) SIGXCPU, SIGXFSZ, -#endif // defined(OS_APPLE) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) SIGIO, -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) }; bool InstallHandlers(const std::vector& signals, @@ -289,7 +290,7 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( // signals that do not re-raise autonomously), such as signals delivered via // kill() and asynchronous hardware faults such as SEGV_MTEAERR, which would // otherwise be lost when re-raising the signal via raise(). -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) int retval = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), @@ -307,7 +308,8 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( if (errno != EPERM) { _exit(kFailureExitCode); } -#endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || + // BUILDFLAG(IS_CHROMEOS) // Explicitly re-raise the signal if it will not re-raise itself. Because // signal handlers normally execute with their signal blocked, this raise() diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index 769483c40d..d9b44de071 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -33,7 +33,7 @@ #include "test/scoped_temp_dir.h" #include "util/posix/scoped_mmap.h" -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) #include #include @@ -57,7 +57,8 @@ #define PR_MTE_TCF_ASYNC (1UL << 2) #endif #endif // defined(ARCH_CPU_ARM64) -#endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || + // BUILDFLAG(IS_CHROMEOS) namespace crashpad { namespace test { @@ -89,15 +90,16 @@ std::vector TestableSignals() { #endif // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL) signals.push_back({SIGPIPE, 0}); signals.push_back({SIGSEGV, 0}); -#if (defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS)) && \ +#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || \ + BUILDFLAG(IS_CHROMEOS)) && \ defined(ARCH_CPU_ARM64) if (getauxval(AT_HWCAP2) & HWCAP2_MTE) { signals.push_back({SIGSEGV, SEGV_MTEAERR}); } #endif -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) signals.push_back({SIGSYS, 0}); -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64) signals.push_back({SIGTRAP, 0}); #endif // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64) @@ -207,7 +209,8 @@ void CauseSignal(int sig, int code) { *i = 0; break; } -#if (defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS)) && \ +#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || \ + BUILDFLAG(IS_CHROMEOS)) && \ defined(ARCH_CPU_ARM64) case SEGV_MTEAERR: { ScopedMmap mapping; @@ -229,13 +232,13 @@ void CauseSignal(int sig, int code) { mapping.addr_as()[1ULL << 56] = 0; break; } -#endif // (defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS)) && - // defined(ARCH_CPU_ARM64) +#endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || + // BUILDFLAG(IS_CHROMEOS)) && defined(ARCH_CPU_ARM64) } break; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) case SIGSYS: { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -247,7 +250,7 @@ void CauseSignal(int sig, int code) { } break; } -#endif // OS_APPLE +#endif // BUILDFLAG(IS_APPLE) #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64) case SIGTRAP: { @@ -520,7 +523,7 @@ TEST(Signals, Raise_HandlerReraisesToDefault) { continue; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (sig == SIGBUS #if defined(ARCH_CPU_ARM64) || sig == SIGILL || sig == SIGSEGV @@ -533,7 +536,7 @@ TEST(Signals, Raise_HandlerReraisesToDefault) { // test must be skipped. continue; } -#endif // defined(OS_APPLE) +#endif // BUILDFLAG(IS_APPLE) SignalsTest test(SignalsTest::TestType::kHandlerReraisesToDefault, SignalsTest::SignalSource::kRaise, @@ -552,7 +555,7 @@ TEST(Signals, Raise_HandlerReraisesToPrevious) { continue; } -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) if (sig == SIGBUS #if defined(ARCH_CPU_ARM64) || sig == SIGILL || sig == SIGSEGV @@ -565,7 +568,7 @@ TEST(Signals, Raise_HandlerReraisesToPrevious) { // test must be skipped. continue; } -#endif // defined(OS_APPLE) +#endif // BUILDFLAG(IS_APPLE) SignalsTest test(SignalsTest::TestType::kHandlerReraisesToPrevious, SignalsTest::SignalSource::kRaise, diff --git a/util/posix/symbolic_constants_posix.cc b/util/posix/symbolic_constants_posix.cc index 671d963403..6bb08960b0 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -29,8 +29,10 @@ namespace { constexpr const char* kSignalNames[] = { nullptr, -#if defined(OS_APPLE) - // sed -Ene 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p' +#if BUILDFLAG(IS_APPLE) + // sed -Ene + // 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ + // "\1",/p' // /usr/include/sys/signal.h // and fix up by removing the entry for SIGPOLL. "HUP", @@ -64,7 +66,7 @@ constexpr const char* kSignalNames[] = { "INFO", "USR1", "USR2", -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #if defined(ARCH_CPU_MIPS_FAMILY) "HUP", "INT", @@ -135,7 +137,7 @@ constexpr const char* kSignalNames[] = { #endif // defined(ARCH_CPU_MIPS_FAMILY) #endif }; -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // NSIG is 64 to account for real-time signals. static_assert(base::size(kSignalNames) == 32, "kSignalNames length"); #else diff --git a/util/posix/symbolic_constants_posix_test.cc b/util/posix/symbolic_constants_posix_test.cc index 61d75e28a8..d59d46c16e 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -35,38 +35,23 @@ constexpr struct { const char* full_name; const char* short_name; } kSignalTestData[] = { - {SIGABRT, "SIGABRT", "ABRT"}, - {SIGALRM, "SIGALRM", "ALRM"}, - {SIGBUS, "SIGBUS", "BUS"}, - {SIGCHLD, "SIGCHLD", "CHLD"}, - {SIGCONT, "SIGCONT", "CONT"}, - {SIGFPE, "SIGFPE", "FPE"}, - {SIGHUP, "SIGHUP", "HUP"}, - {SIGILL, "SIGILL", "ILL"}, - {SIGINT, "SIGINT", "INT"}, - {SIGIO, "SIGIO", "IO"}, - {SIGKILL, "SIGKILL", "KILL"}, - {SIGPIPE, "SIGPIPE", "PIPE"}, - {SIGPROF, "SIGPROF", "PROF"}, - {SIGQUIT, "SIGQUIT", "QUIT"}, - {SIGSEGV, "SIGSEGV", "SEGV"}, - {SIGSTOP, "SIGSTOP", "STOP"}, - {SIGSYS, "SIGSYS", "SYS"}, - {SIGTERM, "SIGTERM", "TERM"}, - {SIGTRAP, "SIGTRAP", "TRAP"}, - {SIGTSTP, "SIGTSTP", "TSTP"}, - {SIGTTIN, "SIGTTIN", "TTIN"}, - {SIGTTOU, "SIGTTOU", "TTOU"}, - {SIGURG, "SIGURG", "URG"}, - {SIGUSR1, "SIGUSR1", "USR1"}, - {SIGUSR2, "SIGUSR2", "USR2"}, - {SIGVTALRM, "SIGVTALRM", "VTALRM"}, - {SIGWINCH, "SIGWINCH", "WINCH"}, - {SIGXCPU, "SIGXCPU", "XCPU"}, -#if defined(OS_APPLE) - {SIGEMT, "SIGEMT", "EMT"}, - {SIGINFO, "SIGINFO", "INFO"}, -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) + {SIGABRT, "SIGABRT", "ABRT"}, {SIGALRM, "SIGALRM", "ALRM"}, + {SIGBUS, "SIGBUS", "BUS"}, {SIGCHLD, "SIGCHLD", "CHLD"}, + {SIGCONT, "SIGCONT", "CONT"}, {SIGFPE, "SIGFPE", "FPE"}, + {SIGHUP, "SIGHUP", "HUP"}, {SIGILL, "SIGILL", "ILL"}, + {SIGINT, "SIGINT", "INT"}, {SIGIO, "SIGIO", "IO"}, + {SIGKILL, "SIGKILL", "KILL"}, {SIGPIPE, "SIGPIPE", "PIPE"}, + {SIGPROF, "SIGPROF", "PROF"}, {SIGQUIT, "SIGQUIT", "QUIT"}, + {SIGSEGV, "SIGSEGV", "SEGV"}, {SIGSTOP, "SIGSTOP", "STOP"}, + {SIGSYS, "SIGSYS", "SYS"}, {SIGTERM, "SIGTERM", "TERM"}, + {SIGTRAP, "SIGTRAP", "TRAP"}, {SIGTSTP, "SIGTSTP", "TSTP"}, + {SIGTTIN, "SIGTTIN", "TTIN"}, {SIGTTOU, "SIGTTOU", "TTOU"}, + {SIGURG, "SIGURG", "URG"}, {SIGUSR1, "SIGUSR1", "USR1"}, + {SIGUSR2, "SIGUSR2", "USR2"}, {SIGVTALRM, "SIGVTALRM", "VTALRM"}, + {SIGWINCH, "SIGWINCH", "WINCH"}, {SIGXCPU, "SIGXCPU", "XCPU"}, +#if BUILDFLAG(IS_APPLE) + {SIGEMT, "SIGEMT", "EMT"}, {SIGINFO, "SIGINFO", "INFO"}, +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) {SIGPWR, "SIGPWR", "PWR"}, #if !defined(ARCH_CPU_MIPS_FAMILY) {SIGSTKFLT, "SIGSTKFLT", "STKFLT"}, @@ -123,7 +108,7 @@ TEST(SymbolicConstantsPOSIX, SignalToString) { kSignalTestData[index].short_name); } -#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // NSIG is 64 to account for real-time signals. constexpr int kSignalCount = 32; #else diff --git a/util/process/process_id.h b/util/process/process_id.h index 113f6fc638..0d8273cc79 100644 --- a/util/process/process_id.h +++ b/util/process/process_id.h @@ -20,27 +20,27 @@ #include "base/format_macros.h" #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) #include #endif namespace crashpad { -#if defined(OS_POSIX) || DOXYGEN +#if BUILDFLAG(IS_POSIX) || DOXYGEN //! \brief Alias for platform-specific type to represent a process. using ProcessID = pid_t; constexpr ProcessID kInvalidProcessID = -1; static_assert(std::is_same::value, "Port."); #define PRI_PROCESS_ID "d" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using ProcessID = DWORD; constexpr ProcessID kInvalidProcessID = 0; #define PRI_PROCESS_ID "lu" -#elif defined(OS_FUCHSIA) +#elif BUILDFLAG(IS_FUCHSIA) using ProcessID = zx_koid_t; constexpr ProcessID kInvalidProcessID = ZX_KOID_INVALID; static_assert(std::is_same::value, "Port."); diff --git a/util/process/process_memory.h b/util/process/process_memory.h index eeb78e97ee..d7e65437d1 100644 --- a/util/process/process_memory.h +++ b/util/process/process_memory.h @@ -22,10 +22,10 @@ #include "build/build_config.h" #include "util/misc/address_types.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include typedef SSIZE_T ssize_t; -#endif // defined(OS_WIN) +#endif // BUILDFLAG(IS_WIN) namespace crashpad { diff --git a/util/process/process_memory_native.h b/util/process/process_memory_native.h index 5a792d76e2..c3b94e826a 100644 --- a/util/process/process_memory_native.h +++ b/util/process/process_memory_native.h @@ -14,26 +14,26 @@ #include "build/build_config.h" -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) #include "util/process/process_memory_fuchsia.h" -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "util/process/process_memory_linux.h" -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include "util/process/process_memory_win.h" -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) #include "util/process/process_memory_mac.h" #endif namespace crashpad { -#if defined(OS_FUCHSIA) || DOXYGEN +#if BUILDFLAG(IS_FUCHSIA) || DOXYGEN //! \brief Alias for platform-specific native implementation of ProcessMemory. using ProcessMemoryNative = ProcessMemoryFuchsia; -#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) using ProcessMemoryNative = ProcessMemoryLinux; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) using ProcessMemoryNative = ProcessMemoryWin; -#elif defined(OS_APPLE) +#elif BUILDFLAG(IS_APPLE) using ProcessMemoryNative = ProcessMemoryMac; #else #error Port. diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index 2e34665fec..78ad81f2cf 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -23,7 +23,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #endif @@ -43,14 +43,15 @@ TEST(ProcessMemoryRange, Basic) { constexpr bool is_64_bit = false; #endif // ARCH_CPU_64_BITS -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(GetSelfProcess())); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(GetSelfProcess())); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) ProcessMemoryRange range; ASSERT_TRUE(range.Initialize(&memory, is_64_bit)); diff --git a/util/process/process_memory_sanitized_test.cc b/util/process/process_memory_sanitized_test.cc index b88eab132d..03eee91928 100644 --- a/util/process/process_memory_sanitized_test.cc +++ b/util/process/process_memory_sanitized_test.cc @@ -14,12 +14,13 @@ #include "util/process/process_memory_sanitized.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/process_type.h" #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #endif @@ -28,14 +29,15 @@ namespace test { namespace { TEST(ProcessMemorySanitized, DenyDisallowedMemory) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(GetSelfProcess())); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(GetSelfProcess())); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) char c = 42; char out; @@ -51,14 +53,15 @@ TEST(ProcessMemorySanitized, DenyDisallowedMemory) { } TEST(ProcessMemorySanitized, AllowedMemory) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(GetSelfProcess())); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(GetSelfProcess())); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) char str[4] = "ABC"; char out[4]; diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc index fe9971bcc7..17df85deda 100644 --- a/util/process/process_memory_test.cc +++ b/util/process/process_memory_test.cc @@ -30,14 +30,15 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include "test/mac/mach_multiprocess.h" -#endif // defined(OS_APPLE) +#endif // BUILDFLAG(IS_APPLE) -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #include "test/linux/fake_ptrace_connection.h" #include "util/linux/direct_ptrace_connection.h" -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) namespace crashpad { namespace test { @@ -47,7 +48,7 @@ namespace { // port which requires root or a code signing entitlement. To account for this // we implement an adaptor class that wraps MachMultiprocess on macOS, because // it shares the child's task port, and makes it behave like MultiprocessExec. -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) class MultiprocessAdaptor : public MachMultiprocess { public: void SetChildTestMainFunction(const std::string& function_name) { @@ -102,7 +103,7 @@ class MultiprocessAdaptor : public MultiprocessExec { void MultiprocessParent() override { Parent(); } }; -#endif // defined(OS_APPLE) +#endif // BUILDFLAG(IS_APPLE) void DoChildReadTestSetup(size_t* region_size, std::unique_ptr* region) { @@ -156,14 +157,15 @@ class ReadTest : public MultiprocessAdaptor { } void DoTest(ProcessType process, size_t region_size, VMAddress address) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) std::unique_ptr result(new char[region_size]); @@ -343,14 +345,15 @@ class ReadCStringTest : public MultiprocessAdaptor { VMAddress local_empty_address, VMAddress local_short_address, VMAddress long_string_address) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) Compare(memory, const_empty_address, kConstCharEmpty); Compare(memory, const_short_address, kConstCharShort); @@ -421,14 +424,15 @@ class ReadUnmappedTest : public MultiprocessAdaptor { } void DoTest(ProcessType process, VMAddress address) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) DirectPtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) VMAddress page_addr1 = address; VMAddress page_addr2 = page_addr1 + base::GetPageSize(); @@ -554,14 +558,15 @@ class ReadCStringUnmappedTest : public MultiprocessAdaptor { void DoTest(ProcessType process, const std::vector& strings) { -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) +#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) DirectPtraceConnection connection; ASSERT_TRUE(connection.Initialize(process)); ProcessMemoryLinux memory(&connection); #else ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); -#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || + // BUILDFLAG(IS_CHROMEOS) std::string result; result.reserve(kChildProcessStringLength + 1); diff --git a/util/stdlib/aligned_allocator.cc b/util/stdlib/aligned_allocator.cc index 797a3ac4f8..8f01c69511 100644 --- a/util/stdlib/aligned_allocator.cc +++ b/util/stdlib/aligned_allocator.cc @@ -18,12 +18,12 @@ #include "build/build_config.h" -#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) +#if BUILDFLAG(IS_POSIX) || defined(_LIBCPP_STD_VER) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include #include -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace { @@ -31,12 +31,12 @@ namespace { // library to do so. This works even if C++ exceptions are disabled, causing // program termination if uncaught. void ThrowBadAlloc() { -#if defined(OS_POSIX) || defined(_LIBCPP_STD_VER) +#if BUILDFLAG(IS_POSIX) || defined(_LIBCPP_STD_VER) // This works with both libc++ and libstdc++. std::__throw_bad_alloc(); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) std::_Xbad_alloc(); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } } // namespace @@ -44,7 +44,7 @@ void ThrowBadAlloc() { namespace crashpad { void* AlignedAllocate(size_t alignment, size_t size) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) // posix_memalign() requires that alignment be at least sizeof(void*), so the // power-of-2 check needs to happen before potentially changing the alignment. if (alignment == 0 || alignment & (alignment - 1)) { @@ -55,22 +55,22 @@ void* AlignedAllocate(size_t alignment, size_t size) { if (posix_memalign(&pointer, std::max(alignment, sizeof(void*)), size) != 0) { ThrowBadAlloc(); } -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) void* pointer = _aligned_malloc(size, alignment); if (pointer == nullptr) { ThrowBadAlloc(); } -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) return pointer; } void AlignedFree(void* pointer) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) free(pointer); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) _aligned_free(pointer); -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } } // namespace crashpad diff --git a/util/stdlib/aligned_allocator_test.cc b/util/stdlib/aligned_allocator_test.cc index 40e14e83fa..ed58d2b951 100644 --- a/util/stdlib/aligned_allocator_test.cc +++ b/util/stdlib/aligned_allocator_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" #include "test/gtest_death.h" -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) #include #endif @@ -91,7 +91,7 @@ TEST(AlignedAllocator, AlignedVector) { } void BadAlignmentTest() { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // Suppress the assertion MessageBox() normally displayed by the CRT in debug // mode. In release mode, _CrtSetReportMode() is #defined to ((int)0), so // |previous| would appear unused, thus the [[maybe_unused]]. @@ -103,7 +103,7 @@ void BadAlignmentTest() { AlignedVector bad_aligned_vector; bad_aligned_vector.push_back(0); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) _CrtSetReportMode(_CRT_ASSERT, previous); #endif } diff --git a/util/stdlib/strnlen.cc b/util/stdlib/strnlen.cc index 872c0eb472..296b13106f 100644 --- a/util/stdlib/strnlen.cc +++ b/util/stdlib/strnlen.cc @@ -14,7 +14,9 @@ #include "util/stdlib/strnlen.h" -#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_7 +#include "build/build_config.h" + +#if BUILDFLAG(IS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_7 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7 // Redeclare a method only available on Mac OS X 10.7 and later to suppress a diff --git a/util/stdlib/strnlen.h b/util/stdlib/strnlen.h index 59253b7517..9fa447c222 100644 --- a/util/stdlib/strnlen.h +++ b/util/stdlib/strnlen.h @@ -20,7 +20,7 @@ #include "build/build_config.h" -#if defined(OS_MAC) +#if BUILDFLAG(IS_MAC) #include #endif @@ -38,7 +38,7 @@ namespace crashpad { //! and not all systems’ standard libraries provide an implementation. size_t strnlen(const char* string, size_t max_length); -#if !defined(OS_MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7 +#if !BUILDFLAG(IS_MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7 inline size_t strnlen(const char* string, size_t max_length) { return ::strnlen(string, max_length); } diff --git a/util/synchronization/semaphore.h b/util/synchronization/semaphore.h index 308b29b034..1bb9e2184b 100644 --- a/util/synchronization/semaphore.h +++ b/util/synchronization/semaphore.h @@ -19,11 +19,11 @@ #include "build/build_config.h" -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) #include #include #else @@ -76,11 +76,11 @@ class Semaphore { void Signal(); private: -#if defined(OS_APPLE) +#if BUILDFLAG(IS_APPLE) dispatch_semaphore_t semaphore_; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) HANDLE semaphore_; -#elif defined(OS_ANDROID) +#elif BUILDFLAG(IS_ANDROID) std::condition_variable cv_; std::mutex mutex_; int value_; diff --git a/util/synchronization/semaphore_posix.cc b/util/synchronization/semaphore_posix.cc index ebe62a4f42..9e55ede720 100644 --- a/util/synchronization/semaphore_posix.cc +++ b/util/synchronization/semaphore_posix.cc @@ -23,11 +23,12 @@ #include "base/check_op.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "build/build_config.h" #include "util/misc/time.h" namespace crashpad { -#if defined(OS_ANDROID) +#if BUILDFLAG(IS_ANDROID) Semaphore::Semaphore(int value) : cv_(), mutex_(), value_(value) {} @@ -63,7 +64,7 @@ void Semaphore::Signal() { cv_.notify_one(); } -#elif !defined(OS_APPLE) +#elif !BUILDFLAG(IS_APPLE) Semaphore::Semaphore(int value) { PCHECK(sem_init(&semaphore_, 0, value) == 0) << "sem_init"; @@ -104,6 +105,6 @@ void Semaphore::Signal() { PCHECK(sem_post(&semaphore_) == 0) << "sem_post"; } -#endif // OS_ANDROID +#endif // BUILDFLAG(IS_ANDROID) } // namespace crashpad diff --git a/util/synchronization/semaphore_test.cc b/util/synchronization/semaphore_test.cc index 5cb91e489f..08fc9e611a 100644 --- a/util/synchronization/semaphore_test.cc +++ b/util/synchronization/semaphore_test.cc @@ -17,11 +17,12 @@ #include #include "base/cxx17_backports.h" +#include "build/build_config.h" #include "gtest/gtest.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace crashpad { namespace test { @@ -60,50 +61,50 @@ TEST(Semaphore, TimedWaitInfinite_1) { } struct ThreadMainInfo { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) pthread_t pthread; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) HANDLE thread; #endif Semaphore* semaphore; size_t iterations; }; -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) void* -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) DWORD WINAPI -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) ThreadMain(void* argument) { ThreadMainInfo* info = reinterpret_cast(argument); for (size_t iteration = 0; iteration < info->iterations; ++iteration) { info->semaphore->Wait(); } -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) return nullptr; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) return 0; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } void StartThread(ThreadMainInfo* info) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int rv = pthread_create(&info->pthread, nullptr, ThreadMain, info); ASSERT_EQ(rv, 0) << "pthread_create"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) info->thread = CreateThread(nullptr, 0, ThreadMain, info, 0, nullptr); ASSERT_NE(info->thread, nullptr) << "CreateThread"; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } void JoinThread(ThreadMainInfo* info) { -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) int rv = pthread_join(info->pthread, nullptr); EXPECT_EQ(rv, 0) << "pthread_join"; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) DWORD result = WaitForSingleObject(info->thread, INFINITE); EXPECT_EQ(result, WAIT_OBJECT_0) << "WaitForSingleObject"; -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) } TEST(Semaphore, Threaded) { diff --git a/util/thread/thread.h b/util/thread/thread.h index e06ca3c9db..25fccb815a 100644 --- a/util/thread/thread.h +++ b/util/thread/thread.h @@ -17,11 +17,11 @@ #include "build/build_config.h" -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) #include -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) #include -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) namespace crashpad { @@ -49,16 +49,16 @@ class Thread { virtual void ThreadMain() = 0; static -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) void* -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) DWORD WINAPI -#endif // OS_POSIX +#endif // BUILDFLAG(IS_POSIX) ThreadEntryThunk(void* argument); -#if defined(OS_POSIX) +#if BUILDFLAG(IS_POSIX) pthread_t platform_thread_; -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) HANDLE platform_thread_; #endif }; diff --git a/util/thread/worker_thread_test.cc b/util/thread/worker_thread_test.cc index 811d09c375..86f8474273 100644 --- a/util/thread/worker_thread_test.cc +++ b/util/thread/worker_thread_test.cc @@ -14,6 +14,7 @@ #include "util/thread/worker_thread.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/clock.h" #include "util/synchronization/semaphore.h" @@ -78,7 +79,7 @@ TEST(WorkerThread, DoWork) { // also somewhat useful. The expected time "should" be ~40-50ms with a work // interval of 0.05s, but on Fuchsia, 1200ms was observed. So, on Fuchsia, use a // much larger timeout. See https://crashpad.chromium.org/bug/231. -#if defined(OS_FUCHSIA) +#if BUILDFLAG(IS_FUCHSIA) constexpr uint64_t kUpperBoundTime = 10; #else constexpr uint64_t kUpperBoundTime = 1; From 1721bb991cd25f5d7099eeff63e4f5e46eaac1b5 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 19 Jan 2022 15:36:06 -0500 Subject: [PATCH 104/478] Remove unused header from client/settings.h Change-Id: I04d065f8f77797e6a301dffde30dcfe376e9a48d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3402639 Reviewed-by: Joshua Peraza Commit-Queue: Mark Mentovai --- client/settings.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/settings.h b/client/settings.h index 82f893a055..e476c60c3b 100644 --- a/client/settings.h +++ b/client/settings.h @@ -17,8 +17,6 @@ #include -#include - #include "base/files/file_path.h" #include "base/scoped_generic.h" #include "build/build_config.h" From 667424894f19f4e83d56920eec94106b526a800c Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 20 Jan 2022 08:57:13 -0800 Subject: [PATCH 105/478] linux: re-order first-chance-handlers, and disabled signal handlers Both running first chance handlers and checking for disabled signal handlers should no longer interact with DumpWithoutCrashing(). First-chance-handlers should also run even with disabled crashpad signal handlers or else those signals would be reported by the next chained signal handlers as crashes. Change-Id: I64b3da42c400a1c431c6228d4da181ed56bfda89 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3403413 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- client/crashpad_client.h | 2 +- client/crashpad_client_linux.cc | 22 ++++---- client/crashpad_client_linux_test.cc | 59 +++++++++++++--------- snapshot/linux/exception_snapshot_linux.cc | 4 ++ 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index a5e54a581f..6944fb6945 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -421,7 +421,7 @@ class CrashpadClient { //! CaptureContext() or similar. static void DumpWithoutCrash(NativeCPUContext* context); - //! \brief Disables any installed crash handler, including any + //! \brief Disables any installed crash handler, not including any //! FirstChanceHandler and crashes the current process. //! //! \param[in] message A message to be logged before crashing. diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 4c9a307c54..cb07ef0880 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -148,17 +148,7 @@ class SignalHandler { // The base implementation for all signal handlers, suitable for calling // directly to simulate signal delivery. - bool HandleCrash(int signo, siginfo_t* siginfo, void* context) { - if (disabled_for_thread_) { - return false; - } - - if (first_chance_handler_ && - first_chance_handler_( - signo, siginfo, static_cast(context))) { - return true; - } - + void HandleCrash(int signo, siginfo_t* siginfo, void* context) { exception_information_.siginfo_address = FromPointerCast( siginfo); @@ -169,7 +159,6 @@ class SignalHandler { ScopedPrSetDumpable set_dumpable(false); HandleCrashImpl(); - return false; } protected: @@ -198,9 +187,16 @@ class SignalHandler { static void HandleOrReraiseSignal(int signo, siginfo_t* siginfo, void* context) { - if (handler_->HandleCrash(signo, siginfo, context)) { + if (handler_->first_chance_handler_ && + handler_->first_chance_handler_( + signo, siginfo, static_cast(context))) { return; } + + if (!handler_->disabled_for_thread_) { + handler_->HandleCrash(signo, siginfo, context); + } + Signals::RestoreHandlerAndReraiseSignalOnReturn( siginfo, handler_->old_actions_.ActionForSignal(signo)); } diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 08c78b0b9c..e58352b071 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -15,6 +15,7 @@ #include "client/crashpad_client.h" #include +#include #include #include #include @@ -108,10 +109,6 @@ class StartHandlerForSelfTest StartHandlerForSelfTestOptions options_; }; -bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) { - return true; -} - bool InstallHandler(CrashpadClient* client, bool start_at_crash, const base::FilePath& handler_path, @@ -222,13 +219,21 @@ int RecurseInfinitely(int* ptr) { } #pragma clang diagnostic pop +sigjmp_buf do_crash_sigjmp_env; + +bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) { + siglongjmp(do_crash_sigjmp_env, 1); + return true; +} + void DoCrash(const StartHandlerForSelfTestOptions& options, CrashpadClient* client) { + if (sigsetjmp(do_crash_sigjmp_env, 1) != 0) { + return; + } + switch (options.crash_type) { case CrashType::kSimulated: - if (options.set_first_chance_handler) { - client->SetFirstChanceExceptionHandler(HandleCrashSuccessfully); - } CRASHPAD_SIMULATE_CRASH(); break; @@ -364,6 +369,10 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) { return EXIT_FAILURE; } + if (options.set_first_chance_handler) { + client.SetFirstChanceExceptionHandler(HandleCrashSuccessfully); + } + #if BUILDFLAG(IS_ANDROID) if (android_set_abort_message) { android_set_abort_message(kTestAbortMessage); @@ -386,17 +395,19 @@ class StartHandlerForSelfInChildTest : public MultiprocessExec { StartHandlerForSelfInChildTest(const StartHandlerForSelfTestOptions& options) : MultiprocessExec(), options_(options) { SetChildTestMainFunction("StartHandlerForSelfTestChild"); - switch (options.crash_type) { - case CrashType::kSimulated: - // kTerminationNormal, EXIT_SUCCESS - break; - case CrashType::kBuiltinTrap: - SetExpectedChildTerminationBuiltinTrap(); - break; - case CrashType::kInfiniteRecursion: - SetExpectedChildTermination(TerminationReason::kTerminationSignal, - SIGSEGV); - break; + if (!options.set_first_chance_handler) { + switch (options.crash_type) { + case CrashType::kSimulated: + // kTerminationNormal, EXIT_SUCCESS + break; + case CrashType::kBuiltinTrap: + SetExpectedChildTerminationBuiltinTrap(); + break; + case CrashType::kInfiniteRecursion: + SetExpectedChildTermination(TerminationReason::kTerminationSignal, + SIGSEGV); + break; + } } } @@ -447,9 +458,12 @@ class StartHandlerForSelfInChildTest : public MultiprocessExec { reports.clear(); ASSERT_EQ(database->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), options_.set_first_chance_handler ? 0u : 1u); - if (options_.set_first_chance_handler) { + bool report_expected = !options_.set_first_chance_handler || + options_.crash_type == CrashType::kSimulated; + ASSERT_EQ(reports.size(), report_expected ? 1u : 0u); + + if (!report_expected) { return; } @@ -463,11 +477,6 @@ class StartHandlerForSelfInChildTest : public MultiprocessExec { }; TEST_P(StartHandlerForSelfTest, StartHandlerInChild) { - if (Options().set_first_chance_handler && - Options().crash_type != CrashType::kSimulated) { - // TODO(jperaza): test first chance handlers with real crashes. - return; - } #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ defined(UNDEFINED_SANITIZER) if (Options().crash_type == CrashType::kInfiniteRecursion) { diff --git a/snapshot/linux/exception_snapshot_linux.cc b/snapshot/linux/exception_snapshot_linux.cc index 6726d04814..efc9e5694e 100644 --- a/snapshot/linux/exception_snapshot_linux.cc +++ b/snapshot/linux/exception_snapshot_linux.cc @@ -24,6 +24,7 @@ #include "util/linux/traits.h" #include "util/misc/reinterpret_bytes.h" #include "util/numeric/safe_assignment.h" +#include "util/posix/signals.h" namespace crashpad { namespace internal { @@ -445,6 +446,9 @@ bool ExceptionSnapshotLinux::ReadSiginfo(ProcessReaderLinux* reader, PUSH_CODE(siginfo.sigval.sigval); break; + case Signals::kSimulatedSigno: + break; + default: LOG(WARNING) << "Unhandled signal " << siginfo.signo; } From fd732953ceb05b8b9ad9bf192c796392a4ad1158 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 20 Jan 2022 09:45:58 -0800 Subject: [PATCH 106/478] linux: handle multi-threaded crashes Handle multiple simultaneous crashes among threads by having the first crashing thread set an atomic flag and subsequently crashing threads check the flag before requesting a dump. If a dump has already been requested, the threads pause on a futex with a timeout in case the crashing thread crashes again or otherwise fails to WakeThreads(). The thread_local disabled_for_thread_ is removed and combined with this flag because accessing thread_locals produces undefined behavior in signal handlers. Bug:crashpad:384, chromium:861730 Change-Id: I83bce36e1010d0635ba8aeac937e150c43a4166f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3403017 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- client/crashpad_client_linux.cc | 63 ++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index cb07ef0880..5e534599d5 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include #include @@ -137,10 +139,14 @@ class SignalHandler { // handler has been installed. static SignalHandler* Get() { return handler_; } - // Disables any installed Crashpad signal handler for the calling thread. If a - // crash signal is received, any previously installed (non-Crashpad) signal - // handler will be restored and the signal reraised. - static void DisableForThread() { disabled_for_thread_ = true; } + // Disables any installed Crashpad signal handler. If a crash signal is + // received, any previously installed (non-Crashpad) signal handler will be + // restored and the signal reraised. + static void Disable() { + if (!handler_->disabled_.test_and_set()) { + handler_->WakeThreads(); + } + } void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { first_chance_handler_ = handler; @@ -183,6 +189,9 @@ class SignalHandler { virtual void HandleCrashImpl() = 0; private: + static constexpr int32_t kDumpNotDone = 0; + static constexpr int32_t kDumpDone = 1; + // The signal handler installed at OS-level. static void HandleOrReraiseSignal(int signo, siginfo_t* siginfo, @@ -193,24 +202,60 @@ class SignalHandler { return; } - if (!handler_->disabled_for_thread_) { + // Only handle the first fatal signal observed. If another thread receives a + // crash signal, it waits for the first dump to complete instead of + // requesting another. + if (!handler_->disabled_.test_and_set()) { handler_->HandleCrash(signo, siginfo, context); + handler_->WakeThreads(); + } else { + // Processes on Android normally have several chained signal handlers that + // co-operate to report crashes. e.g. WebView will have this signal + // handler installed, the app embedding WebView may have a signal handler + // installed, and Bionic will have a signal handler. Each signal handler + // runs in succession, possibly managed by libsigchain. This wait is + // intended to avoid ill-effects from multiple signal handlers from + // different layers (possibly all trying to use ptrace()) from running + // simultaneously. It does not block forever so that in most conditions, + // those signal handlers will still have a chance to run and ensures + // process termination in case the first crashing thread crashes again in + // its signal handler. Though less typical, this situation also occurs on + // other Linuxes, e.g. to produce in-process stack traces for debug + // builds. + handler_->WaitForDumpDone(); } Signals::RestoreHandlerAndReraiseSignalOnReturn( siginfo, handler_->old_actions_.ActionForSignal(signo)); } + void WaitForDumpDone() { + kernel_timespec timeout; + timeout.tv_sec = 5; + timeout.tv_nsec = 0; + sys_futex(&dump_done_futex_, + FUTEX_WAIT_PRIVATE, + kDumpNotDone, + &timeout, + nullptr, + 0); + } + + void WakeThreads() { + dump_done_futex_ = kDumpDone; + sys_futex( + &dump_done_futex_, FUTEX_WAKE_PRIVATE, INT_MAX, nullptr, nullptr, 0); + } + Signals::OldActions old_actions_ = {}; ExceptionInformation exception_information_ = {}; CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; + int32_t dump_done_futex_ = kDumpNotDone; + std::atomic_flag disabled_ = ATOMIC_FLAG_INIT; static SignalHandler* handler_; - - static thread_local bool disabled_for_thread_; }; SignalHandler* SignalHandler::handler_ = nullptr; -thread_local bool SignalHandler::disabled_for_thread_ = false; // Launches a single use handler to snapshot this process. class LaunchAtCrashHandler : public SignalHandler { @@ -664,7 +709,7 @@ void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { // static void CrashpadClient::CrashWithoutDump(const std::string& message) { - SignalHandler::DisableForThread(); + SignalHandler::Disable(); LOG(FATAL) << message; } From 1cf99ea4d2f4d844f5158433142cf1510b34429d Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 20 Jan 2022 10:04:00 -0700 Subject: [PATCH 107/478] [Crashpad/iOS] Harden CrashHandler against crashes during intermediate dump processing https://crrev.com/c/3399252 fixed a heap overrun in iOS intermediate dump processing. This is a follow-up to that change to harden `CrashHandler` against similar crashes: 1) Ensure the destructor of `ScopedAlternateWriter` is invoked to restore `InProcessHandler::writer_` state before processing the intermediate dump (otherwise, a signal raised by the intermediate dump handler would dereference the empty `std::unique_ptr` in `InProcessHandler::writer_`). 2) Harden `InProcessHandler` to check if `writer_` is empty before handling signals or exceptions Change-Id: I1e63a496395b26681632302e8915b4433897037a Bug: 391 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3401766 Reviewed-by: Justin Cohen Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- client/crashpad_client_ios.cc | 21 +++++++++++++++------ client/ios_handler/in_process_handler.cc | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 01d3484579..467cc0cfaf 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -106,13 +106,22 @@ class CrashHandler : public Thread, void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - internal::InProcessHandler::ScopedAlternateWriter scoper( - &in_process_handler_); - if (scoper.Open()) { - DumpWithContext(context); - if (process_dump) { - in_process_handler_.ProcessIntermediateDump(scoper.path()); + base::FilePath path; + { + // Ensure ScopedAlternateWriter's destructor is invoked before processing + // the dump, or else any crashes handled during dump processing cannot be + // written. + internal::InProcessHandler::ScopedAlternateWriter scoper( + &in_process_handler_); + if (!scoper.Open()) { + LOG(ERROR) << "Could not open writer, ignoring dump request."; + return; } + DumpWithContext(context); + path = scoper.path(); + } + if (process_dump) { + in_process_handler_.ProcessIntermediateDump(path); } } diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index 6058e3b3f1..ea86f39ebf 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -24,6 +24,7 @@ #include "minidump/minidump_file_writer.h" #include "util/file/directory_reader.h" #include "util/file/filesystem.h" +#include "util/ios/raw_logging.h" namespace { @@ -116,6 +117,10 @@ void InProcessHandler::DumpExceptionFromSignal( siginfo_t* siginfo, ucontext_t* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!writer_) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer_"); + return; + } { ScopedReport report(writer_.get(), system_data, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromSignal( @@ -135,6 +140,10 @@ void InProcessHandler::DumpExceptionFromMachException( ConstThreadState old_state, mach_msg_type_number_t old_state_count) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!writer_) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer_"); + return; + } { ScopedReport report(writer_.get(), system_data, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromMachException( @@ -155,6 +164,12 @@ void InProcessHandler::DumpExceptionFromNSExceptionFrames( const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!writer_) { + CRASHPAD_RAW_LOG( + "Cannot DumpExceptionFromNSExceptionFrames without writer_"); + return; + } { ScopedReport report( writer_.get(), system_data, annotations_, frames, num_frames); @@ -318,6 +333,7 @@ InProcessHandler::ScopedReport::ScopedReport( frames_(frames), num_frames_(num_frames), rootMap_(writer) { + DCHECK(writer); InProcessIntermediateDumpHandler::WriteHeader(writer); InProcessIntermediateDumpHandler::WriteProcessInfo(writer, annotations); InProcessIntermediateDumpHandler::WriteSystemInfo(writer, system_data); From 50531fc68fa220f0ce7f178571493c8660a7688c Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 20 Jan 2022 11:36:38 -0800 Subject: [PATCH 108/478] linux: fix missing includes and warnings Change-Id: If83d74d86f4792ad8f8c4c62116457d1126ae9e9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3404959 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- client/crashpad_client_linux.cc | 2 ++ client/crashpad_client_linux_test.cc | 3 +++ 2 files changed, 5 insertions(+) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 5e534599d5..35742be01f 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -28,6 +28,8 @@ #include #include +#include + #include "base/logging.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index e58352b071..4a2bb4189a 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -223,7 +223,10 @@ sigjmp_buf do_crash_sigjmp_env; bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) { siglongjmp(do_crash_sigjmp_env, 1); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code-return" return true; +#pragma clang diagnostic pop } void DoCrash(const StartHandlerForSelfTestOptions& options, From b25b523d3085df5e65006221ea169018321b9b14 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 20 Jan 2022 12:16:41 -0500 Subject: [PATCH 109/478] ios: Simplify testBadAccess by removing optimizations. The badAccess test may return different mach exception codes depending on optimization levels. Simplify by this by turning off optimization for this particular test. Also removes testSegv, which was duplicative and not really testing SIGSEGV. Change-Id: Idb92731da6a86545ed83c2bbdd200a0b792c579f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3403040 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- test/ios/crash_type_xctest.mm | 28 ++++---------------- test/ios/host/cptest_application_delegate.mm | 9 +++---- test/ios/host/cptest_shared_object.h | 3 --- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 3613e220ec..5198d057da 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -16,6 +16,7 @@ #include #import "Service/Sources/EDOClientService.h" +#include "build/build_config.h" #import "test/ios/host/cptest_shared_object.h" #include "util/mach/exception_types.h" #include "util/mach/mach_extensions.h" @@ -85,19 +86,6 @@ - (void)testEDO { XCTAssertEqualObjects(result, @"crashpad"); } -- (void)testSegv { - [rootObject_ crashSegv]; -#if defined(NDEBUG) -#if TARGET_OS_SIMULATOR - [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; -#else - [self verifyCrashReportException:EXC_BREAKPOINT]; -#endif -#else - [self verifyCrashReportException:EXC_BAD_ACCESS]; -#endif -} - - (void)testKillAbort { [rootObject_ crashKillAbort]; [self verifyCrashReportException:EXC_SOFT_SIGNAL]; @@ -108,10 +96,12 @@ - (void)testKillAbort { - (void)testTrap { [rootObject_ crashTrap]; -#if TARGET_OS_SIMULATOR +#if defined(ARCH_CPU_X86_64) [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; -#else +#elif defined(ARCH_CPU_ARM64) [self verifyCrashReportException:EXC_BREAKPOINT]; +#else +#error Port to your CPU architecture #endif } @@ -125,15 +115,7 @@ - (void)testAbort { - (void)testBadAccess { [rootObject_ crashBadAccess]; -#if defined(NDEBUG) -#if TARGET_OS_SIMULATOR - [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; -#else - [self verifyCrashReportException:EXC_BREAKPOINT]; -#endif -#else [self verifyCrashReportException:EXC_BAD_ACCESS]; -#endif } - (void)testException { diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 3bf39dfec0..212ab693e5 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -241,7 +241,9 @@ - (NSDictionary*)getProcessAnnotations { return [dict passByValue]; } -- (void)crashBadAccess { +// Use [[clang::optnone]] here to get consistent exception codes, otherwise the +// exception can change depending on optimization level. +- (void)crashBadAccess [[clang::optnone]] { strcpy(nullptr, "bla"); } @@ -249,11 +251,6 @@ - (void)crashKillAbort { kill(getpid(), SIGABRT); } -- (void)crashSegv { - long* zero = nullptr; - *zero = 0xc045004d; -} - - (void)crashTrap { __builtin_trap(); } diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index 90e3de8d38..2fe36c556d 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -58,9 +58,6 @@ // Triggers a crash with a call to kill(SIGABRT). - (void)crashKillAbort; -// Triggers a segfault crash. -- (void)crashSegv; - // Trigger a crash with a __builtin_trap. - (void)crashTrap; From 496d522cc43957bf3e8e645d8d3224f2c279c21c Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 20 Jan 2022 13:26:49 -0500 Subject: [PATCH 110/478] ios: Add comment explaining why iOS only installs a SIGABRT handler. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xnu turns hardware faults into Mach exceptions, so the only signal left to register is SIGABRT, which never starts off as a hardware fault. Installing a handler for other signals would lead to recording exceptions twice. As a consequence, Crashpad will not generate intermediate dumps for anything manually calling raise(SIG*). In practice, this doesn’t actually happen for crash signals that originate as hardware faults. Change-Id: I1be669d10e89b8e8ebcc69cfdf79c1ee20c96f76 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3403042 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- client/crashpad_client_ios.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 467cc0cfaf..7c378ba7f7 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -71,6 +71,13 @@ class CrashHandler : public Thread, if (!in_process_handler_.Initialize( database, url, annotations, system_data_) || !InstallMachExceptionHandler() || + // xnu turns hardware faults into Mach exceptions, so the only signal + // left to register is SIGABRT, which never starts off as a hardware + // fault. Installing a handler for other signals would lead to + // recording exceptions twice. As a consequence, Crashpad will not + // generate intermediate dumps for anything manually calling + // raise(SIG*). In practice, this doesn’t actually happen for crash + // signals that originate as hardware faults. !Signals::InstallHandler(SIGABRT, CatchSignal, 0, &old_action_)) { LOG(ERROR) << "Unable to initialize Crashpad."; return false; From 30d302a8ca4bd5d9b392f5f4a6fa4460f350e39b Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 26 Jan 2022 14:43:08 -0500 Subject: [PATCH 111/478] ios: Speed up XCUITests by swizzling away Xcode crash check. Change-Id: Iadda950544448d771960d35fd064f5287bce0484 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3410579 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- test/ios/crash_type_xctest.mm | 38 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 5198d057da..1022d29111 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -34,8 +34,20 @@ @interface CPTestTestCase : XCTestCase { @implementation CPTestTestCase + (void)setUp { - // Swizzle away the handleCrashUnderSymbol callback. Without this, any time - // the host app is intentionally crashed, the test is immediately failed. + [CPTestTestCase swizzleHandleCrashUnderSymbol]; + [CPTestTestCase swizleMayTerminateOutOfBandWithoutCrashReport]; + + // Override EDO default error handler. Without this, the default EDO error + // handler will throw an error and fail the test. + EDOSetClientErrorHandler(^(NSError* error){ + // Do nothing. + }); +} + +// Swizzle away the -[XCUIApplicationImpl handleCrashUnderSymbol:] callback. +// Without this, any time the host app is intentionally crashed, the test is +// immediately failed. ++ (void)swizzleHandleCrashUnderSymbol { SEL originalSelector = NSSelectorFromString(@"handleCrashUnderSymbol:"); SEL swizzledSelector = @selector(handleCrashUnderSymbol:); Method originalMethod = class_getInstanceMethod( @@ -43,12 +55,20 @@ + (void)setUp { Method swizzledMethod = class_getInstanceMethod([self class], swizzledSelector); method_exchangeImplementations(originalMethod, swizzledMethod); +} - // Override EDO default error handler. Without this, the default EDO error - // handler will throw an error and fail the test. - EDOSetClientErrorHandler(^(NSError* error){ - // Do nothing. - }); +// Swizzle away the time consuming 'Checking for crash reports corresponding to' +// from -[XCUIApplicationProcess swizleMayTerminateOutOfBandWithoutCrashReport] +// that is unnecessary for these tests. ++ (void)swizleMayTerminateOutOfBandWithoutCrashReport { + SEL originalSelector = + NSSelectorFromString(@"mayTerminateOutOfBandWithoutCrashReport"); + SEL swizzledSelector = @selector(mayTerminateOutOfBandWithoutCrashReport); + Method originalMethod = class_getInstanceMethod( + objc_getClass("XCUIApplicationProcess"), originalSelector); + Method swizzledMethod = + class_getInstanceMethod([self class], swizzledSelector); + method_exchangeImplementations(originalMethod, swizzledMethod); } // This gets called after tearDown, so there's no straightforward way to @@ -57,6 +77,10 @@ + (void)setUp { - (void)handleCrashUnderSymbol:(id)arg1 { } +- (BOOL)mayTerminateOutOfBandWithoutCrashReport { + return YES; +} + - (void)setUp { app_ = [[XCUIApplication alloc] init]; [app_ launch]; From 36ad57186286ac6511ce149fd51e1b52c2d3e2e4 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Sat, 22 Jan 2022 20:57:40 -0500 Subject: [PATCH 112/478] ios: Add MemorySnapshotIOSIntermediateDumpTest. Change-Id: Ib8b962c631d6ae90fb1805dff5e28ab078940328 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3401570 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- snapshot/BUILD.gn | 1 + ...ory_snapshot_ios_intermediate_dump_test.cc | 161 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 snapshot/ios/memory_snapshot_ios_intermediate_dump_test.cc diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index e3ad7f67e7..1a1d8935c9 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -364,6 +364,7 @@ source_set("snapshot_test") { if (crashpad_is_ios) { sources += [ + "ios/memory_snapshot_ios_intermediate_dump_test.cc", "ios/process_snapshot_ios_intermediate_dump_test.cc", "mac/cpu_context_mac_test.cc", ] diff --git a/snapshot/ios/memory_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/memory_snapshot_ios_intermediate_dump_test.cc new file mode 100644 index 0000000000..bbe2a88bd5 --- /dev/null +++ b/snapshot/ios/memory_snapshot_ios_intermediate_dump_test.cc @@ -0,0 +1,161 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "snapshot/ios/memory_snapshot_ios_intermediate_dump.h" + +#include +#include + +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { +namespace { + +using internal::MemorySnapshotIOSIntermediateDump; + +const vm_address_t kDefaultAddress = 0x1000; + +class ReadToString : public crashpad::MemorySnapshot::Delegate { + public: + const std::string& result() { return result_; } + + private: + // MemorySnapshot::Delegate: + bool MemorySnapshotDelegateRead(void* data, size_t size) override { + result_ = std::string(reinterpret_cast(data), size); + return true; + } + + std::string result_; +}; + +std::unique_ptr CreateMemorySnapshot( + vm_address_t address, + std::vector& data) { + auto memory = std::make_unique(); + memory->Initialize( + address, reinterpret_cast(data.data()), data.size()); + return memory; +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, MergeSame) { + std::vector data(10, 'a'); + auto memory = CreateMemorySnapshot(kDefaultAddress, data); + std::unique_ptr merged( + memory->MergeWithOtherSnapshot(memory.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress); + EXPECT_EQ(merged->Size(), data.size()); + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "aaaaaaaaaa"); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, MergeNoOverlap) { + std::vector data1(10, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(10, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress + 10, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress); + EXPECT_EQ(merged->Size(), 20u); + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "aaaaaaaaaabbbbbbbbbb"); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, MergePartial) { + std::vector data1(10, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(10, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress + 5, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress); + EXPECT_EQ(merged->Size(), 15u); + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "aaaaabbbbbbbbbb"); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, NoMerge) { + std::vector data1(10, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(10, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress + 20, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged.get(), nullptr); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, EnvelopeBiggerFirst) { + std::vector data1(30, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(10, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress + 15, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress); + EXPECT_EQ(merged->Size(), data1.size()); + + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, EnvelopeBiggerSecond) { + std::vector data1(10, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(20, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress); + EXPECT_EQ(merged->Size(), data2.size()); + + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "bbbbbbbbbbbbbbbbbbbb"); +} + +TEST(MemorySnapshotIOSIntermediateDumpTest, SmallerAddressSecond) { + std::vector data1(10, 'a'); + auto memory1 = CreateMemorySnapshot(kDefaultAddress, data1); + + std::vector data2(20, 'b'); + auto memory2 = CreateMemorySnapshot(kDefaultAddress - 10, data2); + + std::unique_ptr merged( + memory1->MergeWithOtherSnapshot(memory2.get())); + EXPECT_EQ(merged->Address(), kDefaultAddress - 10); + EXPECT_EQ(merged->Size(), data2.size()); + ReadToString delegate; + merged->Read(&delegate); + EXPECT_EQ(delegate.result(), "bbbbbbbbbbbbbbbbbbbb"); +} + +} // namespace +} // namespace test +} // namespace crashpad From 55eb7a2eafe2b5a4983fa20053d240802cfee15e Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 2 Feb 2022 12:24:47 -0500 Subject: [PATCH 113/478] ios: Add ability to reset Crashpad client for iOS tests. Change-Id: I83df67d77367ef01731bd9af015605cfa19e972e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3418581 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- client/crashpad_client.h | 5 ++ client/crashpad_client_ios.cc | 40 ++++++++++++-- client/crashpad_client_ios_test.mm | 70 +++++++++++++----------- client/ios_handler/exception_processor.h | 4 ++ 4 files changed, 84 insertions(+), 35 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 6944fb6945..da4abe4713 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -558,6 +558,11 @@ class CrashpadClient { static void DumpWithoutCrashAndDeferProcessingAtPath( NativeCPUContext* context, const base::FilePath path); + + //! \brief Unregister the Crashpad client. Intended to be used by tests so + //! multiple Crashpad clients can be started and stopped. Not expected to + //! be used in a shipping application. + static void ResetForTesting(); #endif #if BUILDFLAG(IS_APPLE) || DOXYGEN diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 7c378ba7f7..7474ed8bdb 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -60,8 +60,14 @@ class CrashHandler : public Thread, CrashHandler& operator=(const CrashHandler&) = delete; static CrashHandler* Get() { - static CrashHandler* instance = new CrashHandler(); - return instance; + if (!instance_) + instance_ = new CrashHandler(); + return instance_; + } + + static void ResetForTesting() { + delete instance_; + instance_ = nullptr; } bool Initialize(const base::FilePath& database, @@ -148,6 +154,12 @@ class CrashHandler : public Thread, private: CrashHandler() = default; + ~CrashHandler() { + UninstallObjcExceptionPreprocessor(); + Signals::InstallDefaultHandler(SIGABRT); + UninstallMachExceptionHandler(); + } + bool InstallMachExceptionHandler() { exception_port_.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); if (!exception_port_.is_valid()) { @@ -180,15 +192,22 @@ class CrashHandler : public Thread, return false; } + mach_handler_running_ = true; Start(); return true; } + void UninstallMachExceptionHandler() { + mach_handler_running_ = false; + exception_port_.reset(); + Join(); + } + // Thread: void ThreadMain() override { UniversalMachExcServer universal_mach_exc_server(this); - while (true) { + while (mach_handler_running_) { mach_msg_return_t mr = MachMessageServer::Run(&universal_mach_exc_server, exception_port_.get(), @@ -196,7 +215,10 @@ class CrashHandler : public Thread, MachMessageServer::kPersistent, MachMessageServer::kReceiveLargeIgnore, kMachMessageTimeoutWaitIndefinitely); - MACH_CHECK(mr == MACH_SEND_INVALID_DEST, mr) << "MachMessageServer::Run"; + MACH_CHECK(mr == (mach_handler_running_ ? MACH_SEND_INVALID_DEST + : MACH_RCV_PORT_CHANGED), + mr) + << "MachMessageServer::Run"; } } @@ -313,9 +335,13 @@ class CrashHandler : public Thread, struct sigaction old_action_ = {}; internal::InProcessHandler in_process_handler_; internal::IOSSystemDataCollector system_data_; + static CrashHandler* instance_; + bool mach_handler_running_ = false; InitializationStateDcheck initialized_; }; +CrashHandler* CrashHandler::instance_ = nullptr; + } // namespace CrashpadClient::CrashpadClient() {} @@ -380,4 +406,10 @@ void CrashpadClient::DumpWithoutCrashAndDeferProcessingAtPath( crash_handler->DumpWithoutCrashAtPath(context, path); } +void CrashpadClient::ResetForTesting() { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + crash_handler->ResetForTesting(); +} + } // namespace crashpad diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm index 3c350e9fd5..a9a00c5951 100644 --- a/client/crashpad_client_ios_test.mm +++ b/client/crashpad_client_ios_test.mm @@ -30,45 +30,61 @@ namespace test { namespace { -using CrashpadIOSClient = PlatformTest; +class CrashpadIOSClient : public testing::Test { + protected: + // testing::Test: -TEST_F(CrashpadIOSClient, DumpWithoutCrash) { - CrashpadClient client; + void SetUp() override { + ASSERT_TRUE(client_.StartCrashpadInProcessHandler( + base::FilePath(database_dir.path()), "", {})); + database_ = CrashReportDatabase::Initialize(database_dir.path()); + } + + void TearDown() override { client_.ResetForTesting(); } + + auto& Client() { return client_; } + auto& Database() { return database_; } + + private: + std::unique_ptr database_; + CrashpadClient client_; ScopedTempDir database_dir; - ASSERT_TRUE(client.StartCrashpadInProcessHandler( - base::FilePath(database_dir.path()), "", {})); - std::unique_ptr database = - CrashReportDatabase::Initialize(database_dir.path()); +}; + +TEST_F(CrashpadIOSClient, DumpWithoutCrash) { std::vector reports; - EXPECT_EQ(database->GetPendingReports(&reports), + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); ASSERT_EQ(reports.size(), 0u); CRASHPAD_SIMULATE_CRASH(); - reports.clear(); - EXPECT_EQ(database->GetPendingReports(&reports), + + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); ASSERT_EQ(reports.size(), 1u); +} +TEST_F(CrashpadIOSClient, DumpWithoutCrashAndDefer) { + std::vector reports; CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING(); - reports.clear(); - EXPECT_EQ(database->GetPendingReports(&reports), + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), 1u); - client.ProcessIntermediateDumps(); - reports.clear(); - EXPECT_EQ(database->GetPendingReports(&reports), + ASSERT_EQ(reports.size(), 0u); + Client().ProcessIntermediateDumps(); + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), 2u); + ASSERT_EQ(reports.size(), 1u); +} +TEST_F(CrashpadIOSClient, DumpWithoutCrashAndDeferAtPath) { + std::vector reports; ScopedTempDir crash_dir; UUID uuid; uuid.InitializeWithNew(); CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING_AT_PATH( crash_dir.path().Append(uuid.ToString())); - reports.clear(); - EXPECT_EQ(database->GetPendingReports(&reports), + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), 2u); + ASSERT_EQ(reports.size(), 0u); NSError* error = nil; NSArray* paths = [[NSFileManager defaultManager] @@ -76,12 +92,12 @@ crash_dir.path().value()) error:&error]; ASSERT_EQ([paths count], 1u); - client.ProcessIntermediateDump( + Client().ProcessIntermediateDump( crash_dir.path().Append([paths[0] fileSystemRepresentation])); reports.clear(); - EXPECT_EQ(database->GetPendingReports(&reports), + EXPECT_EQ(Database()->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), 3u); + ASSERT_EQ(reports.size(), 1u); } // This test is covered by a similar XCUITest, but for development purposes it's @@ -89,10 +105,6 @@ // to correctly run this in Google Test. Leave the test here, disabled, for use // during development only. TEST_F(CrashpadIOSClient, DISABLED_ThrowNSException) { - CrashpadClient client; - ScopedTempDir database_dir; - ASSERT_TRUE(client.StartCrashpadInProcessHandler( - base::FilePath(database_dir.path()), "", {})); [NSException raise:@"GoogleTestNSException" format:@"ThrowException"]; } @@ -101,10 +113,6 @@ // to correctly run this in Google Test. Leave the test here, disabled, for use // during development only. TEST_F(CrashpadIOSClient, DISABLED_ThrowException) { - CrashpadClient client; - ScopedTempDir database_dir; - ASSERT_TRUE(client.StartCrashpadInProcessHandler( - base::FilePath(database_dir.path()), "", {})); std::vector empty_vector; empty_vector.at(42); } diff --git a/client/ios_handler/exception_processor.h b/client/ios_handler/exception_processor.h index 7318e21446..893e475c54 100644 --- a/client/ios_handler/exception_processor.h +++ b/client/ios_handler/exception_processor.h @@ -59,6 +59,10 @@ class ObjcExceptionDelegate { //! signal handler. It should only be installed once. void InstallObjcExceptionPreprocessor(ObjcExceptionDelegate* delegate); +//! \brief Uninstalls the Objective-C exception preprocessor. Expected to be +//! used by tests only. +void UninstallObjcExceptionPreprocessor(); + } // namespace crashpad #endif // CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ From f96b86e3604b8e6201bbf1e66c629f96f8f62caa Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 2 Feb 2022 13:41:48 -0800 Subject: [PATCH 114/478] Upgrade builders to Ubuntu-18.04 Change-Id: I5f918b37b8eef1ef23930f0570df5baea7f52fad Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3433272 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- infra/config/generated/cr-buildbucket.cfg | 24 +++++++++++------------ infra/config/generated/project.cfg | 2 +- infra/config/main.star | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 44075a3552..a79e5cfa44 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -23,7 +23,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -57,7 +57,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -91,7 +91,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -124,7 +124,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -303,7 +303,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -336,7 +336,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -537,7 +537,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -568,7 +568,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -599,7 +599,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -629,7 +629,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -793,7 +793,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -823,7 +823,7 @@ buckets { swarming_host: "chromium-swarm.appspot.com" dimensions: "cores:8" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" + dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" diff --git a/infra/config/generated/project.cfg b/infra/config/generated/project.cfg index 168ec5e99e..9fd3699a8a 100644 --- a/infra/config/generated/project.cfg +++ b/infra/config/generated/project.cfg @@ -7,7 +7,7 @@ name: "crashpad" access: "group:all" lucicfg { - version: "1.30.4" + version: "1.30.9" package_dir: ".." config_dir: "generated" entry_point: "main.star" diff --git a/infra/config/main.star b/infra/config/main.star index 1069520f49..6a0a68f9e8 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -153,11 +153,11 @@ def crashpad_dimensions(platform, bucket): dimensions["pool"] = "luci.flex." + bucket if platform == "fuchsia": - dimensions["os"] = "Ubuntu-16.04" + dimensions["os"] = "Ubuntu-18.04" elif platform == "ios": dimensions["os"] = "Mac-11" elif platform == "linux": - dimensions["os"] = "Ubuntu-16.04" + dimensions["os"] = "Ubuntu-18.04" elif platform == "mac": dimensions["os"] = "Mac-11" elif platform == "win": From d4649818767f9bb873e1740b7f50533d438f1985 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 2 Feb 2022 14:02:27 -0800 Subject: [PATCH 115/478] Use atomics in metrics recording terminate handler Accessing static data which requires dynamic initialization produces undefined behavior in signal handlers. Bug: crashpad:384 Change-Id: Ic100c8b34cb61a8ed76bd09e5a1178086d31fd68 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3433270 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- handler/handler_main.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index cb78aa1680..48ef8b6530 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -286,10 +287,10 @@ bool AddKeyValueToMap(std::map* map, // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after // something else logs an exit event. void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { - [[maybe_unused]] static bool once = [](Metrics::LifetimeMilestone milestone) { + static std::atomic_flag metrics_exit_recorded = ATOMIC_FLAG_INIT; + if (!metrics_exit_recorded.test_and_set()) { Metrics::HandlerLifetimeMilestone(milestone); - return true; - }(milestone); + } } // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for From 45cc0da93a59dde3ced8f5e6befc970a179a00d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kempe?= Date: Tue, 8 Feb 2022 08:14:02 +0000 Subject: [PATCH 116/478] arm64: Add Armv8.3-A PAC support to assembly files This patch adds optional support for Arm Pointer Authentication Codes. X30/LR is not stored to stack at any place and restored for usage. Therefore only adding PAC flag to .note.gnu.property section. Change-Id: I9581059dfa1eed88af5a73df15b6a0d299caea13 Bug: crashpad: 1145581 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3440070 Reviewed-by: Mark Mentovai Commit-Queue: Adenilson Cavalcanti --- client/crashpad_info_note.S | 2 +- snapshot/crashpad_info_size_test_note.S | 2 +- snapshot/elf/elf_image_reader_test_note.S | 2 +- .../{arm64_bti_note.S => arm64_pac_bti.S} | 49 +++++++++++++------ util/misc/capture_context_linux.S | 7 +-- 5 files changed, 41 insertions(+), 21 deletions(-) rename util/misc/{arm64_bti_note.S => arm64_pac_bti.S} (63%) diff --git a/client/crashpad_info_note.S b/client/crashpad_info_note.S index ef3d68ccb4..80de22d606 100644 --- a/client/crashpad_info_note.S +++ b/client/crashpad_info_note.S @@ -17,7 +17,7 @@ // that symbol to be in the dynamic symbol table. #include "util/misc/elf_note_types.h" -#include "util/misc/arm64_bti_note.S" +#include "util/misc/arm64_pac_bti.S" // namespace crashpad { // CrashpadInfo g_crashpad_info; diff --git a/snapshot/crashpad_info_size_test_note.S b/snapshot/crashpad_info_size_test_note.S index 8b1a0bd842..ebc0d8f6d7 100644 --- a/snapshot/crashpad_info_size_test_note.S +++ b/snapshot/crashpad_info_size_test_note.S @@ -17,7 +17,7 @@ // that symbol to be in the dynamic symbol table. #include "util/misc/elf_note_types.h" -#include "util/misc/arm64_bti_note.S" +#include "util/misc/arm64_pac_bti.S" // namespace crashpad { // CrashpadInfo g_test_crashpad_info; diff --git a/snapshot/elf/elf_image_reader_test_note.S b/snapshot/elf/elf_image_reader_test_note.S index 08f1829fe4..b6c17ff327 100644 --- a/snapshot/elf/elf_image_reader_test_note.S +++ b/snapshot/elf/elf_image_reader_test_note.S @@ -13,7 +13,7 @@ // limitations under the License. #include "util/misc/elf_note_types.h" -#include "util/misc/arm64_bti_note.S" +#include "util/misc/arm64_pac_bti.S" #define NOTE_ALIGN 4 .section .note.crashpad.test,"a",%note diff --git a/util/misc/arm64_bti_note.S b/util/misc/arm64_pac_bti.S similarity index 63% rename from util/misc/arm64_bti_note.S rename to util/misc/arm64_pac_bti.S index 987493be81..ac90f2abec 100644 --- a/util/misc/arm64_bti_note.S +++ b/util/misc/arm64_pac_bti.S @@ -12,16 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_UTIL_MISC_ARM64_BTI_NOTE_S -#define CRASHPAD_UTIL_MISC_ARM64_BTI_NOTE_S +#ifndef CRASHPAD_UTIL_MISC_ARM64_PAC_BTI_S +#define CRASHPAD_UTIL_MISC_ARM64_PAC_BTI_S -/* Support macros for the Armv8.5-A Branch Target Identification feature which - * requires emitting a .note.gnu.property section with the appropriate +/* Support macros for the Armv8.5-A Branch Target Identification and + * Armv8.3-A Pointer Authentication features which require emitting + * a .note.gnu.property section with the appropriate * architecture-dependent feature bits set. * Read more: "ELF for the Arm® 64-bit Architecture" */ #if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT == 1) -#define GNU_PROPERTY_AARCH64_BTI (1 << 0) // Has BTI +#define GNU_PROPERTY_AARCH64_BTI 1 // Has BTI +#define CRASHPAD_AARCH64_VALID_JUMP_CALL_TARGET bti jc +#define CRASHPAD_AARCH64_VALID_CALL_TARGET bti c +#define CRASHPAD_AARCH64_VALID_JUMP_TARGET bti j +#else +#define GNU_PROPERTY_AARCH64_BTI 0 // No BTI +#define CRASHPAD_AARCH64_VALID_JUMP_CALL_TARGET +#define CRASHPAD_AARCH64_VALID_CALL_TARGET +#define CRASHPAD_AARCH64_VALID_JUMP_TARGET +#endif + +#if defined(__ARM_FEATURE_PAC_DEFAULT) +#if ((__ARM_FEATURE_PAC_DEFAULT & ((1<<0)|(1<<2))) == 0) +#error Pointer authentication defines no valid key! +#endif +#define GNU_PROPERTY_AARCH64_PAC 1 // Has PAC +#else +#define GNU_PROPERTY_AARCH64_PAC 0 // No PAC +#endif + +/** + * Emit a proper .note.gnu.property section in case of PAC or BTI being enabled. + */ +#if (GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_PAC != 0) .pushsection .note.gnu.property, "a" .balign 4 .long 0x4 /* size of field "GNU" */ @@ -30,17 +54,12 @@ .asciz "GNU" .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ .long 0x4 - .long GNU_PROPERTY_AARCH64_BTI + .long ((GNU_PROPERTY_AARCH64_BTI<<0)|(GNU_PROPERTY_AARCH64_PAC<<1)) .long 0x0 .popsection -#define CRASHPAD_AARCH64_VALID_JUMP_CALL_TARGET bti jc -#define CRASHPAD_AARCH64_VALID_CALL_TARGET bti c -#define CRASHPAD_AARCH64_VALID_JUMP_TARGET bti j -#undef GNU_PROPERTY_AARCH64_BTI -#else -#define CRASHPAD_AARCH64_VALID_JUMP_CALL_TARGET -#define CRASHPAD_AARCH64_VALID_CALL_TARGET -#define CRASHPAD_AARCH64_VALID_JUMP_TARGET #endif -#endif /* CRASHPAD_UTIL_MISC_ARM64_BTI_NOTE_S */ +#undef GNU_PROPERTY_AARCH64_BTI +#undef GNU_PROPERTY_AARCH64_PAC + +#endif /* CRASHPAD_UTIL_MISC_ARM64_PAC_BTI_S */ diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index 0ee561f534..96e030d902 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "util/misc/arm64_bti_note.S" +#include "util/misc/arm64_pac_bti.S" // namespace crashpad { // void CaptureContext(ucontext_t* context); @@ -316,14 +316,15 @@ CAPTURECONTEXT_SYMBOL2: stp x26, x27, [x0, #0x188] stp x28, x29, [x0, #0x198] - // The original LR can't be recovered. + // The original LR can't be recovered, therefore no need to sign x30 with PAC. str x30, [x0, #0x1a8] // Use x1 as a scratch register. mov x1, SP str x1, [x0, #0x1b0] // context->uc_mcontext.sp - // The link register holds the return address for this function. + // The link register holds the return address for this function and won't be + // recovered, therefore no need to sign x30 with PAC. str x30, [x0, #0x1b8] // context->uc_mcontext.pc // pstate should hold SPSR but NZCV are the only bits we know about. From d78c03600c2bceb8cbeafeaeaf7a7dbe85f43eee Mon Sep 17 00:00:00 2001 From: Vadim Shtayura Date: Wed, 9 Feb 2022 12:20:35 -0800 Subject: [PATCH 117/478] Switch to shorter bucket names in luci-scheduler.cfg. This is an ongoing LUCI config migration. R=jperaza@chromium.org Change-Id: If4a85cf8c9156cacee0305566a345ac1de498d93 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3449163 Reviewed-by: Joshua Peraza Commit-Queue: Joshua Peraza --- infra/config/generated/luci-scheduler.cfg | 28 +++++++++++------------ infra/config/generated/project.cfg | 1 + infra/config/main.star | 5 +++- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index 6b3d04d1b3..a2251eb899 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg @@ -10,7 +10,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_fuchsia_arm64_dbg" } } @@ -20,7 +20,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_fuchsia_arm64_rel" } } @@ -30,7 +30,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_fuchsia_x64_dbg" } } @@ -40,7 +40,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_fuchsia_x64_rel" } } @@ -50,7 +50,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_ios_arm64_dbg" } } @@ -60,7 +60,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_ios_arm64_rel" } } @@ -70,7 +70,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_ios_x64_dbg" } } @@ -80,7 +80,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_ios_x64_rel" } } @@ -90,7 +90,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_linux_x64_dbg" } } @@ -100,7 +100,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_linux_x64_rel" } } @@ -110,7 +110,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_mac_x64_dbg" } } @@ -120,7 +120,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_mac_x64_rel" } } @@ -130,7 +130,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_win_x64_dbg" } } @@ -140,7 +140,7 @@ job { acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" - bucket: "luci.crashpad.ci" + bucket: "ci" builder: "crashpad_win_x64_rel" } } diff --git a/infra/config/generated/project.cfg b/infra/config/generated/project.cfg index 9fd3699a8a..28e9f2e62e 100644 --- a/infra/config/generated/project.cfg +++ b/infra/config/generated/project.cfg @@ -11,4 +11,5 @@ lucicfg { package_dir: ".." config_dir: "generated" entry_point: "main.star" + experiments: "crbug.com/1182002" } diff --git a/infra/config/main.star b/infra/config/main.star index 6a0a68f9e8..fade252303 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -13,11 +13,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -lucicfg.check_version("1.28.0", "Please update depot_tools") +lucicfg.check_version("1.30.9", "Please update depot_tools") REPO_URL = "https://chromium.googlesource.com/crashpad/crashpad" REVIEW_URL = "https://chromium-review.googlesource.com/crashpad/crashpad" +# Use LUCI Scheduler BBv2 names and add Scheduler realms configs. +lucicfg.enable_experiment("crbug.com/1182002") + luci.project( name = "crashpad", buildbucket = "cr-buildbucket.appspot.com", From be4fb6a412e894d6817df815d8b1889c191f0f8c Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Thu, 10 Feb 2022 08:49:53 -0800 Subject: [PATCH 118/478] win: Get correct version info from registry kernel32.dll no longer works as a source of truth for Windows versions because it is not updated with every Windows update. This change grabs the last two version numbers from the registry, if possible. This also copies some code cleanup from Chromium (crrev.com/c/3205913). Bug: chromium:1248324 Change-Id: I9d6745084060f033cd54c56f832aed4ac163e6be Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3434090 Reviewed-by: Joshua Peraza Reviewed-by: Mark Mentovai Commit-Queue: Bruce Dawson --- snapshot/win/system_snapshot_win.cc | 117 ++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 15 deletions(-) diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index 905976d8b2..ba1c1e7532 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -14,11 +14,14 @@ #include "snapshot/win/system_snapshot_win.h" -#include #include #include +#include #include +// Must be after windows.h. +#include + #include #include #include @@ -30,6 +33,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "util/stdlib/string_number_conversion.h" #include "util/win/module_version.h" #include "util/win/scoped_registry_key.h" @@ -67,6 +71,50 @@ std::string GetStringForFileOS(uint32_t file_os) { return "Unknown"; } +//! \brief Reads a DWORD from the registry and returns it as an int. +bool ReadRegistryDWORD(HKEY key, const wchar_t* name, int* out_value) { + DWORD type; + DWORD local_value; + DWORD size = sizeof(local_value); + if (RegQueryValueEx(key, + name, + nullptr, + &type, + reinterpret_cast(&local_value), + &size) == ERROR_SUCCESS && + type == REG_DWORD) { + *out_value = static_cast(local_value); + return true; + } + return false; +} + +//! \brief Reads a string from the registry and returns it as an int. +bool ReadRegistryDWORDFromSZ(HKEY key, const char* name, int* out_value) { + char string_value[11]; + DWORD type; + // Leave space for a terminating zero. + DWORD size = sizeof(string_value) - sizeof(string_value[0]); + // Use the 'A' version of this function so that we can use + // StringToNumber. + if (RegQueryValueExA(key, + name, + nullptr, + &type, + reinterpret_cast(&string_value), + &size) == ERROR_SUCCESS && + type == REG_SZ) { + // Make sure the string is null-terminated. + string_value[size / sizeof(string_value[0])] = '\0'; + unsigned local_value; + if (StringToNumber(string_value, &local_value)) { + *out_value = local_value; + return true; + } + } + return false; +} + } // namespace namespace internal { @@ -89,16 +137,50 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { process_reader_ = process_reader; - // We use both GetVersionEx() and GetModuleVersionAndType() (which uses - // VerQueryValue() internally). GetVersionEx() is not trustworthy after - // Windows 8 (depending on the application manifest) so its data is used only - // to fill the os_server_ field, and the rest comes from the version - // information stamped on kernel32.dll. - OSVERSIONINFOEX version_info = {sizeof(version_info)}; - if (!GetVersionEx(reinterpret_cast(&version_info))) { - PLOG(WARNING) << "GetVersionEx"; - } else { - os_server_ = version_info.wProductType != VER_NT_WORKSTATION; + // We use both IsWindowsServer() (which uses VerifyVersionInfo() internally) + // and GetModuleVersionAndType() (which uses VerQueryValue() internally). + // VerifyVersionInfo() is not trustworthy after Windows 8 (depending on the + // application manifest) so its data is used only to fill the os_server_ + // field, and the rest comes from the version information stamped on + // kernel32.dll and from the registry. + os_server_ = IsWindowsServer(); + + // kernel32.dll used to be a good way to get a non-lying version number, but + // kernel32.dll has been refactored into multiple DLLs so it sometimes does + // not get updated when a new version of Windows ships, especially on + // Windows 11. Additionally, pairs of releases such as 19041/19042 + // (20H1/20H2) actually have identical code and have their differences + // enabled by a configuration setting. Therefore the recommended way to get + // OS version information on recent versions of Windows is to read it from the + // registry. If any of the version-number components are missing from the + // registry (on Windows 7, for instance) then kernel32.dll is used as a + // fallback. + bool version_data_found = false; + int os_version_build = 0; + HKEY key; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + 0, + KEY_QUERY_VALUE, + &key) == ERROR_SUCCESS) { + ScopedRegistryKey scoped_key(key); + + // Read the four components of the version from the registry. + // UBR apparently stands for Update Build Revision and it goes up every + // month when patches are installed. The full version is stored in the + // registry as: + // CurrentMajorVersionNumber.CurrentMinorVersionNumber.CurrentBuildNumber.UBR + if (ReadRegistryDWORD( + key, L"CurrentMajorVersionNumber", &os_version_major_) && + ReadRegistryDWORD( + key, L"CurrentMinorVersionNumber", &os_version_minor_) && + ReadRegistryDWORDFromSZ( + key, "CurrentBuildNumber", &os_version_bugfix_) && + ReadRegistryDWORD(key, L"UBR", &os_version_build)) { + // Since we found all four components in the registry we don't need + // to read them from kernel32.dll. + version_data_found = true; + } } static constexpr wchar_t kSystemDll[] = L"kernel32.dll"; @@ -106,10 +188,15 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) { std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags); std::string os_name = GetStringForFileOS(ffi.dwFileOS); - os_version_major_ = ffi.dwFileVersionMS >> 16; - os_version_minor_ = ffi.dwFileVersionMS & 0xffff; - os_version_bugfix_ = ffi.dwFileVersionLS >> 16; - os_version_build_ = base::StringPrintf("%lu", ffi.dwFileVersionLS & 0xffff); + if (!version_data_found) { + os_version_major_ = ffi.dwFileVersionMS >> 16; + os_version_minor_ = ffi.dwFileVersionMS & 0xffff; + os_version_bugfix_ = ffi.dwFileVersionLS >> 16; + os_version_build = static_cast(ffi.dwFileVersionLS & 0xffff); + } + + os_version_build_ = base::StringPrintf("%u", os_version_build); + os_version_full_ = base::StringPrintf( "%s %u.%u.%u.%s%s", os_name.c_str(), From 0830895880fa1204bd52f3f836ad05f9aafdc3c0 Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Sat, 12 Feb 2022 13:33:39 -1000 Subject: [PATCH 119/478] ios: Remove unused vector include When updating Chromium's copy of crashpad I received this very reasonable warning: client\ios_handler\exception_processor.h: Includes STL header(s) but does not reference std:: So, this change removes the #include of vector. Change-Id: I22f05b542fd4e0b582351072a3e3bb4af402b836 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3459402 Reviewed-by: Mark Mentovai Reviewed-by: Justin Cohen Commit-Queue: Bruce Dawson --- client/ios_handler/exception_processor.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/ios_handler/exception_processor.h b/client/ios_handler/exception_processor.h index 893e475c54..9be63134da 100644 --- a/client/ios_handler/exception_processor.h +++ b/client/ios_handler/exception_processor.h @@ -15,8 +15,6 @@ #ifndef CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ #define CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ -#include - #include "util/misc/capture_context.h" namespace crashpad { From 4112c11b773019cf7d923fb3b8b0d7c31ddfb320 Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Sat, 12 Feb 2022 13:36:12 -1000 Subject: [PATCH 120/478] ios: Use PlatformTest instead of testing::Test When trying to update Chromium's copy of crashpad I got this error message: Banned functions were used. third_party\crashpad\crashpad\client\crashpad_client_ios_test.mm:33: testing::Test should not be used in Objective-C++ code as it does not drain the autorelease pool at the end of the test. Use PlatformTest instead. So, I'm fixing the code as requested. The change was introduced in crrev.com/c/3418581 Change-Id: I4888febbd41b6365d9bde5ad062565770496243f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3459403 Reviewed-by: Justin Cohen Commit-Queue: Bruce Dawson --- client/crashpad_client_ios_test.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm index a9a00c5951..9800d4092e 100644 --- a/client/crashpad_client_ios_test.mm +++ b/client/crashpad_client_ios_test.mm @@ -30,7 +30,7 @@ namespace test { namespace { -class CrashpadIOSClient : public testing::Test { +class CrashpadIOSClient : public PlatformTest { protected: // testing::Test: From e9937cb36cd12f24d73a07c4b91168cf1885b5db Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Wed, 9 Feb 2022 13:30:54 -0700 Subject: [PATCH 121/478] [Cleanup] Fix circular dependency on Windows. Crashpad currently has a circular dependency: client->snapshot->client. The dependency from snapshot -> client only exists to pull in a single constant for Windows (CrashpadClient::kTriggeredExceptionCode), so this change breaks the dependency by splitting the constant out into a new file util/win/exception_codes.h. Change-Id: I6b74b367df716e097758e63a44c53cb92ea5e04d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3450763 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- client/crashpad_client.h | 11 ------ client/crashpad_client_win.cc | 3 +- handler/win/crash_other_program.cc | 3 +- snapshot/BUILD.gn | 5 --- snapshot/win/exception_snapshot_win.cc | 4 +-- snapshot/win/exception_snapshot_win_test.cc | 1 - util/BUILD.gn | 1 + util/win/exception_codes.h | 37 +++++++++++++++++++++ 8 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 util/win/exception_codes.h diff --git a/client/crashpad_client.h b/client/crashpad_client.h index da4abe4713..54acfba9c3 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -702,17 +702,6 @@ class CrashpadClient { static bool DumpAndCrashTargetProcess(HANDLE process, HANDLE blame_thread, DWORD exception_code); - - enum : uint32_t { - //! \brief The exception code (roughly "Client called") used when - //! DumpAndCrashTargetProcess() triggers an exception in a target - //! process. - //! - //! \note This value does not have any bits of the top nibble set, to avoid - //! confusion with real exception codes which tend to have those bits - //! set. - kTriggeredExceptionCode = 0xcca11ed, - }; #endif #if BUILDFLAG(IS_APPLE) || DOXYGEN diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 0973c2a672..1275d7d75b 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -36,6 +36,7 @@ #include "util/win/command_line.h" #include "util/win/context_wrappers.h" #include "util/win/critical_section_with_debug_info.h" +#include "util/win/exception_codes.h" #include "util/win/get_function.h" #include "util/win/handle.h" #include "util/win/initial_client_data.h" @@ -926,7 +927,7 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process, // ecx = kTriggeredExceptionCode for dwExceptionCode. data_to_write.push_back(0xb9); - AddUint32(&data_to_write, kTriggeredExceptionCode); + AddUint32(&data_to_write, ExceptionCodes::kTriggeredExceptionCode); // jmp to RaiseException() via rax. data_to_write.push_back(0x48); // mov rax, imm. diff --git a/handler/win/crash_other_program.cc b/handler/win/crash_other_program.cc index bbd25af5df..3020f6621f 100644 --- a/handler/win/crash_other_program.cc +++ b/handler/win/crash_other_program.cc @@ -24,6 +24,7 @@ #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" +#include "util/win/exception_codes.h" #include "util/win/scoped_handle.h" #include "util/win/xp_compat.h" @@ -108,7 +109,7 @@ int CrashOtherProgram(int argc, wchar_t* argv[]) { DWORD expect_exit_code; if (argc == 3 && wcscmp(argv[2], L"noexception") == 0) { - expect_exit_code = CrashpadClient::kTriggeredExceptionCode; + expect_exit_code = ExceptionCodes::kTriggeredExceptionCode; if (!CrashpadClient::DumpAndCrashTargetProcess( child.process_handle(), 0, 0)) return EXIT_FAILURE; diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 1a1d8935c9..ea2412a0bf 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -254,7 +254,6 @@ crashpad_static_library("snapshot") { ] if (crashpad_is_win) { - deps += [ "../client" ] cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union libs = [ "powrprof.lib" ] } @@ -442,10 +441,6 @@ source_set("snapshot_test") { "../util", ] - if (crashpad_is_win) { - deps += [ "../client" ] - } - if (crashpad_is_ios) { deps += [ ":snapshot_test_ios_data", diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index 5b306cd5bf..29cf165d19 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -15,13 +15,13 @@ #include "snapshot/win/exception_snapshot_win.h" #include "base/logging.h" -#include "client/crashpad_client.h" #include "snapshot/capture_memory.h" #include "snapshot/memory_snapshot.h" #include "snapshot/memory_snapshot_generic.h" #include "snapshot/win/capture_memory_delegate_win.h" #include "snapshot/win/cpu_context_win.h" #include "snapshot/win/process_reader_win.h" +#include "util/win/exception_codes.h" #include "util/win/nt_internals.h" namespace crashpad { @@ -215,7 +215,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( } const bool triggered_by_client = - first_record.ExceptionCode == CrashpadClient::kTriggeredExceptionCode && + first_record.ExceptionCode == ExceptionCodes::kTriggeredExceptionCode && first_record.NumberParameters == 2; if (triggered_by_client) process_reader->DecrementThreadSuspendCounts(exception_thread_id); diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index dbf9cfc059..91ff48fa10 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -18,7 +18,6 @@ #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" -#include "client/crashpad_client.h" #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" #include "test/errors.h" diff --git a/util/BUILD.gn b/util/BUILD.gn index 586b79ca7b..d5e63d2dff 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -468,6 +468,7 @@ crashpad_static_library("util") { "win/critical_section_with_debug_info.h", "win/exception_handler_server.cc", "win/exception_handler_server.h", + "win/exception_codes.h", "win/get_function.cc", "win/get_function.h", "win/get_module_information.cc", diff --git a/util/win/exception_codes.h b/util/win/exception_codes.h new file mode 100644 index 0000000000..eca940c3a3 --- /dev/null +++ b/util/win/exception_codes.h @@ -0,0 +1,37 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_WIN_EXCEPTION_CODES_H_ +#define CRASHPAD_UTIL_WIN_EXCEPTION_CODES_H_ + +#include + +namespace crashpad { + +//! \brief Crashpad-specific exception codes that are used as arguments to +//! `RaiseException()` in unusual circumstances. +enum ExceptionCodes : uint32_t { + //! \brief The exception code (roughly "Client called") used when + //! DumpAndCrashTargetProcess() triggers an exception in a target + //! process. + //! + //! \note This value does not have any bits of the top nibble set, to avoid + //! confusion with real exception codes which tend to have those bits + //! set. + kTriggeredExceptionCode = 0xcca11ed, +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_EXCEPTION_CODES_H_ From 2bb6f068a8fcd08f6eeb725d7b00b06ac9c279b6 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 24 Feb 2022 16:38:28 -0500 Subject: [PATCH 122/478] Fix off-by-one error in ModuleSnapshotMinidump DebugFileName. Strings in minidumps are typically NUL-terminated (https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_string). But the CodeViewRecord types do not use MINDIUMP_STRINGs, and do not have a separate length field for the pdb_name. Instead, the strings are always NUL-terminated, with the length derived from the MINIDUMP_LOCATION_DESCRIPTOR::DataSize field. The writer is correctly NUL-terminating the debug filename, but ModuleSnapshotMinidump is off-by-one and including the NUL-terminator. Change-Id: I8d813b5ef9e9e167dca73a6a938fbbf8dd1580c2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3482876 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- snapshot/minidump/module_snapshot_minidump.cc | 10 ++++++++-- snapshot/minidump/process_snapshot_minidump_test.cc | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/snapshot/minidump/module_snapshot_minidump.cc b/snapshot/minidump/module_snapshot_minidump.cc index 698f535741..7dad87a663 100644 --- a/snapshot/minidump/module_snapshot_minidump.cc +++ b/snapshot/minidump/module_snapshot_minidump.cc @@ -100,7 +100,7 @@ bool ModuleSnapshotMinidump::InitializeModuleCodeView( signature = *reinterpret_cast(cv_record.data()); if (signature == CodeViewRecordPDB70::kSignature) { - if (cv_record.size() < offsetof(CodeViewRecordPDB70, pdb_name)) { + if (cv_record.size() < offsetof(CodeViewRecordPDB70, pdb_name) + 1) { LOG(ERROR) << "CodeView record in module marked as PDB70 but too small"; return false; } @@ -111,8 +111,14 @@ bool ModuleSnapshotMinidump::InitializeModuleCodeView( age_ = cv_record_pdb70->age; uuid_ = cv_record_pdb70->uuid; + if (cv_record.back() != '\0') { + LOG(ERROR) << "CodeView record marked as PDB70 missing NUL-terminator in " + "pdb_name"; + return false; + } + std::copy(cv_record.begin() + offsetof(CodeViewRecordPDB70, pdb_name), - cv_record.end(), + cv_record.end() - 1, std::back_inserter(debug_file_name_)); return true; } diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index b9fa23d73c..3c5dcf6c23 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -350,6 +350,7 @@ TEST(ProcessSnapshotMinidump, Modules) { "libgeorgism", "librealistutopia", }; + constexpr char debug_name[] = "debugme.pdb"; minidump_module.BaseOfImage = 0xbadf00d; minidump_module.SizeOfImage = 9001; @@ -373,12 +374,15 @@ TEST(ProcessSnapshotMinidump, Modules) { pdb70_cv.signature = CodeViewRecordPDB70::kSignature; pdb70_cv.age = 7; pdb70_cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff"); - pdb70_cv.pdb_name[0] = '\0'; auto pdb70_loc = static_cast(string_file.SeekGet()); - auto pdb70_size = sizeof(pdb70_cv); + auto pdb70_size = offsetof(CodeViewRecordPDB70, pdb_name); - EXPECT_TRUE(string_file.Write(&pdb70_cv, sizeof(pdb70_cv))); + EXPECT_TRUE(string_file.Write(&pdb70_cv, pdb70_size)); + + size_t nul_terminated_length = strlen(debug_name) + 1; + EXPECT_TRUE(string_file.Write(debug_name, nul_terminated_length)); + pdb70_size += nul_terminated_length; CodeViewRecordBuildID build_id_cv; build_id_cv.signature = CodeViewRecordBuildID::kSignature; @@ -545,6 +549,7 @@ TEST(ProcessSnapshotMinidump, Modules) { EXPECT_EQ(uuid.ToString(), "00112233-4455-6677-8899-aabbccddeeff"); EXPECT_EQ(age, 7U); + EXPECT_EQ(modules[i]->DebugFileName(), debug_name); } else { auto build_id = modules[i]->BuildID(); std::string build_id_text(build_id.data(), From 0affe616899ec552ffb63a663bdc12abb80a815e Mon Sep 17 00:00:00 2001 From: Daniel Cheng Date: Mon, 28 Feb 2022 20:57:19 -0800 Subject: [PATCH 123/478] Migrate base::{size,empty,data} to STL equivalents in crashpad. Bug: chromium:1299695 Change-Id: I95187a425b08c96430c659f843c379d506972f0f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3496462 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- client/crash_report_database_mac.mm | 6 +- client/crashpad_client_ios.cc | 8 +- .../in_process_intermediate_dump_handler.cc | 7 +- ..._process_intermediate_dump_handler_test.cc | 5 +- client/simulate_crash_mac.cc | 7 +- client/simulate_crash_mac_test.cc | 9 ++- handler/mac/file_limit_annotation.cc | 4 +- handler/win/crashy_test_program.cc | 6 +- handler/win/hanging_program.cc | 5 +- minidump/minidump_annotation_writer_test.cc | 4 +- minidump/minidump_byte_array_writer_test.cc | 6 +- minidump/minidump_exception_writer_test.cc | 4 +- minidump/minidump_file_writer_test.cc | 4 +- minidump/minidump_memory_writer_test.cc | 8 +- minidump/minidump_misc_info_writer.cc | 10 +-- minidump/minidump_misc_info_writer_test.cc | 52 ++++++------- ...nidump_module_crashpad_info_writer_test.cc | 8 +- minidump/minidump_module_writer_test.cc | 12 +-- minidump/minidump_rva_list_writer_test.cc | 6 +- minidump/minidump_string_writer_test.cc | 15 ++-- minidump/minidump_system_info_writer.cc | 5 +- minidump/minidump_thread_id_map_test.cc | 7 +- minidump/minidump_thread_writer_test.cc | 12 +-- minidump/minidump_writable.cc | 5 +- minidump/test/minidump_context_test_util.cc | 73 +++++++++---------- snapshot/capture_memory.cc | 8 +- snapshot/cpu_context.cc | 7 +- snapshot/cpu_context_test.cc | 23 +++--- .../memory_map_region_snapshot_fuchsia.cc | 5 +- .../fuchsia/process_reader_fuchsia_test.cc | 5 +- .../fuchsia/process_snapshot_fuchsia_test.cc | 13 ++-- .../linux/exception_snapshot_linux_test.cc | 13 ++-- snapshot/linux/process_reader_linux_test.cc | 4 +- snapshot/mac/mach_o_image_reader.cc | 7 +- .../mac/mach_o_image_segment_reader_test.cc | 9 ++- snapshot/mac/process_reader_mac_test.cc | 8 +- snapshot/mac/process_types.cc | 4 +- snapshot/mac/process_types/custom.cc | 9 +-- snapshot/mac/process_types_test.cc | 8 +- .../minidump/minidump_context_converter.cc | 19 ++--- .../process_snapshot_minidump_test.cc | 24 +++--- snapshot/posix/timezone.cc | 6 +- snapshot/posix/timezone_test.cc | 4 +- .../process_snapshot_sanitized_test.cc | 5 +- .../sanitization_information_test.cc | 5 +- snapshot/test/test_cpu_context.cc | 32 ++++---- snapshot/win/cpu_context_win_test.cc | 9 ++- .../crashpad_snapshot_test_image_reader.cc | 9 ++- snapshot/win/pe_image_annotations_reader.cc | 6 +- snapshot/win/pe_image_reader.cc | 4 +- snapshot/win/process_reader_win_test.cc | 7 +- snapshot/win/process_snapshot_win.cc | 8 +- test/hex_string.h | 4 +- test/hex_string_test.cc | 5 +- tools/crashpad_database_util.cc | 10 +-- util/file/delimited_file_reader.cc | 4 +- util/file/delimited_file_reader_test.cc | 8 +- util/file/file_io_test.cc | 4 +- util/linux/proc_stat_reader.cc | 5 +- util/linux/proc_task_reader.cc | 5 +- util/linux/ptrace_client.cc | 4 +- util/mac/checked_mach_address_range_test.cc | 8 +- util/mac/launchd_test.mm | 10 +-- util/mach/child_port_handshake.cc | 6 +- util/mach/child_port_server.cc | 5 +- .../composite_mach_message_server_test.cc | 15 ++-- util/mach/exc_client_variants_test.cc | 11 +-- util/mach/exc_server_variants.cc | 8 +- util/mach/exc_server_variants_test.cc | 41 ++++++----- util/mach/exception_behaviors_test.cc | 5 +- util/mach/exception_types_test.cc | 9 ++- util/mach/mach_message_server_test.cc | 4 +- util/mach/notify_server.cc | 5 +- util/mach/symbolic_constants_mach.cc | 28 +++---- util/mach/symbolic_constants_mach_test.cc | 50 ++++++------- util/misc/arraysize.h | 6 +- util/misc/capture_context_test_util_win.cc | 11 +-- util/misc/clock_test.cc | 4 +- util/misc/paths_win.cc | 11 ++- util/misc/random_string_test.cc | 6 +- util/misc/uuid_test.cc | 8 +- util/net/http_transport_socket.cc | 8 +- util/net/http_transport_win.cc | 5 +- util/numeric/checked_address_range_test.cc | 8 +- util/numeric/checked_range_test.cc | 12 +-- util/posix/close_multiple.cc | 4 +- util/posix/process_info_mac.cc | 11 +-- util/posix/scoped_mmap_test.cc | 17 +++-- util/posix/signals.cc | 13 ++-- util/posix/signals_test.cc | 4 +- util/posix/symbolic_constants_posix.cc | 11 +-- util/posix/symbolic_constants_posix_test.cc | 15 ++-- util/process/process_memory_range_test.cc | 14 ++-- util/stdlib/string_number_conversion_test.cc | 6 +- util/stdlib/strlcpy_test.cc | 14 ++-- util/stdlib/thread_safe_vector_test.cc | 11 +-- util/stream/base94_output_stream_test.cc | 4 +- util/stream/zlib_output_stream.cc | 9 ++- util/stream/zlib_output_stream_test.cc | 4 +- util/synchronization/semaphore_test.cc | 7 +- util/thread/thread_log_messages_test.cc | 9 ++- util/win/command_line_test.cc | 17 +++-- util/win/exception_handler_server.cc | 6 +- util/win/ntstatus_logging.cc | 4 +- util/win/registration_protocol_win.cc | 10 +-- util/win/safe_terminate_process_test.cc | 6 +- 106 files changed, 556 insertions(+), 522 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 52319bef8a..c24b4a5dee 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -14,9 +14,9 @@ #include "client/crash_report_database.h" +#import #include #include -#import #include #include #include @@ -25,9 +25,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/mac/scoped_nsautorelease_pool.h" #include "base/posix/eintr_wrapper.h" @@ -282,7 +282,7 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, } // Create the three processing directories for the database. - for (size_t i = 0; i < base::size(kReportDirectories); ++i) { + for (size_t i = 0; i < std::size(kReportDirectories); ++i) { if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) return false; } diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 7474ed8bdb..ae0ddf1d48 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -17,8 +17,8 @@ #include #include +#include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" @@ -40,7 +40,7 @@ bool IsBeingDebugged() { kinfo_proc kern_proc_info; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; size_t len = sizeof(kern_proc_info); - if (sysctl(mib, base::size(mib), &kern_proc_info, &len, nullptr, 0) == 0) + if (sysctl(mib, std::size(mib), &kern_proc_info, &len, nullptr, 0) == 0) return kern_proc_info.kp_proc.p_flag & P_TRACED; return false; } @@ -111,7 +111,7 @@ class CrashHandler : public Thread, mach_thread_self(), kSimulatedException, code, - base::size(code), + std::size(code), MACHINE_THREAD_STATE, reinterpret_cast(context), MACHINE_THREAD_STATE_COUNT); @@ -304,7 +304,7 @@ class CrashHandler : public Thread, mach_thread_self(), kMachExceptionFromNSException, code, - base::size(code), + std::size(code), MACHINE_THREAD_STATE, reinterpret_cast(context), MACHINE_THREAD_STATE_COUNT); diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index 12dcf2b49f..e4d6223ba0 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -21,7 +21,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "build/build_config.h" #include "snapshot/snapshot_constants.h" #include "util/ios/ios_intermediate_dump_writer.h" @@ -428,7 +429,7 @@ void CaptureMemoryPointedToByThreadState(IOSIntermediateDumpWriter* writer, MaybeCaptureMemoryAround(writer, thread_state.__rip); #elif defined(ARCH_CPU_ARM_FAMILY) MaybeCaptureMemoryAround(writer, thread_state.__pc); - for (size_t i = 0; i < base::size(thread_state.__x); ++i) { + for (size_t i = 0; i < std::size(thread_state.__x); ++i) { MaybeCaptureMemoryAround(writer, thread_state.__x[i]); } #endif @@ -598,7 +599,7 @@ void InProcessIntermediateDumpHandler::WriteProcessInfo( kinfo_proc kern_proc_info; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()}; size_t len = sizeof(kern_proc_info); - if (sysctl(mib, base::size(mib), &kern_proc_info, &len, nullptr, 0) == 0) { + if (sysctl(mib, std::size(mib), &kern_proc_info, &len, nullptr, 0) == 0) { WriteProperty( writer, IntermediateDumpKey::kPID, &kern_proc_info.kp_proc.p_pid); WriteProperty(writer, diff --git a/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/client/ios_handler/in_process_intermediate_dump_handler_test.cc index b79f93f67b..54af2c7f0d 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler_test.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/files/file_path.h" #include "build/build_config.h" #include "client/annotation.h" @@ -74,7 +75,7 @@ class InProcessIntermediateDumpHandlerTest : public testing::Test { mach_thread_self(), kSimulatedException, code, - base::size(code), + std::size(code), MACHINE_THREAD_STATE, reinterpret_cast(&cpu_context), MACHINE_THREAD_STATE_COUNT); diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc index 48d81a0d9c..86f4043d6e 100644 --- a/client/simulate_crash_mac.cc +++ b/client/simulate_crash_mac.cc @@ -17,8 +17,9 @@ #include #include +#include + #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" @@ -207,7 +208,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) { base::mac::ScopedMachSendRight thread(mach_thread_self()); exception_type_t exception = kMachExceptionSimulated; mach_exception_data_type_t codes[] = {0, 0}; - mach_msg_type_number_t code_count = base::size(codes); + mach_msg_type_number_t code_count = std::size(codes); // Look up the handler for EXC_CRASH exceptions in the same way that the // kernel would: try a thread handler, then a task handler, and finally a host @@ -229,7 +230,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) { bool success = false; for (size_t target_type_index = 0; - !success && target_type_index < base::size(kTargetTypes); + !success && target_type_index < std::size(kTargetTypes); ++target_type_index) { ExceptionPorts::ExceptionHandlerVector handlers; ExceptionPorts exception_ports(kTargetTypes[target_type_index], diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc index f22b2a69de..ccd0267c31 100644 --- a/client/simulate_crash_mac_test.cc +++ b/client/simulate_crash_mac_test.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -370,13 +371,13 @@ TEST(SimulateCrash, SimulateCrash) { #endif }; - for (size_t target_index = 0; target_index < base::size(kTargets); + for (size_t target_index = 0; target_index < std::size(kTargets); ++target_index) { TestSimulateCrashMac::ExceptionPortsTarget target = kTargets[target_index]; SCOPED_TRACE(base::StringPrintf( "target_index %zu, target %d", target_index, target)); - for (size_t behavior_index = 0; behavior_index < base::size(kBehaviors); + for (size_t behavior_index = 0; behavior_index < std::size(kBehaviors); ++behavior_index) { exception_behavior_t behavior = kBehaviors[behavior_index]; SCOPED_TRACE(base::StringPrintf( @@ -390,7 +391,7 @@ TEST(SimulateCrash, SimulateCrash) { target, behavior, THREAD_STATE_NONE); test_simulate_crash_mac.Run(); } else { - for (size_t flavor_index = 0; flavor_index < base::size(kFlavors); + for (size_t flavor_index = 0; flavor_index < std::size(kFlavors); ++flavor_index) { thread_state_flavor_t flavor = kFlavors[flavor_index]; SCOPED_TRACE(base::StringPrintf( diff --git a/handler/mac/file_limit_annotation.cc b/handler/mac/file_limit_annotation.cc index 0813b9502c..063345343d 100644 --- a/handler/mac/file_limit_annotation.cc +++ b/handler/mac/file_limit_annotation.cc @@ -21,9 +21,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" @@ -108,7 +108,7 @@ void RecordFileLimitAnnotation() { int mib[] = {CTL_KERN, KERN_MAXFILES}; size = sizeof(value); std::string max_files = FormatFromSysctl( - sysctl(mib, base::size(mib), &value, &size, nullptr, 0), &value, &size); + sysctl(mib, std::size(mib), &value, &size, nullptr, 0), &value, &size); std::string open_files = CountOpenFileDescriptors(); diff --git a/handler/win/crashy_test_program.cc b/handler/win/crashy_test_program.cc index 4fb2554774..f5cf04877b 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -19,12 +19,12 @@ #include #include +#include #include #include #include #include -#include "base/cxx17_backports.h" #include "base/files/file_path.h" #include "base/logging.h" #include "build/build_config.h" @@ -83,11 +83,11 @@ void AllocateMemoryOfVariousProtections() { // All of these allocations are leaked, we want to view them in windbg via // !vprot. void* reserve = VirtualAlloc( - nullptr, base::size(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); + nullptr, std::size(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); PCHECK(reserve) << "VirtualAlloc MEM_RESERVE"; uintptr_t reserve_as_int = reinterpret_cast(reserve); - for (size_t i = 0; i < base::size(kPageTypes); ++i) { + for (size_t i = 0; i < std::size(kPageTypes); ++i) { void* result = VirtualAlloc(reinterpret_cast(reserve_as_int + (kPageSize * i)), kPageSize, diff --git a/handler/win/hanging_program.cc b/handler/win/hanging_program.cc index b65d46db82..aff3ae28e6 100644 --- a/handler/win/hanging_program.cc +++ b/handler/win/hanging_program.cc @@ -15,7 +15,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/debug/alias.h" #include "base/logging.h" #include "base/notreached.h" @@ -125,7 +126,7 @@ int wmain(int argc, wchar_t* argv[]) { // This is not expected to return. DWORD count = WaitForMultipleObjects( - static_cast(base::size(threads)), threads, true, INFINITE); + static_cast(std::size(threads)), threads, true, INFINITE); if (count == WAIT_FAILED) { PLOG(ERROR) << "WaitForMultipleObjects"; } else { diff --git a/minidump/minidump_annotation_writer_test.cc b/minidump/minidump_annotation_writer_test.cc index c862f023e5..ff3c2a8e3c 100644 --- a/minidump/minidump_annotation_writer_test.cc +++ b/minidump/minidump_annotation_writer_test.cc @@ -14,9 +14,9 @@ #include "minidump/minidump_annotation_writer.h" +#include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" #include "minidump/minidump_extensions.h" #include "minidump/test/minidump_byte_array_writer_test_util.h" @@ -107,7 +107,7 @@ TEST(MinidumpAnnotationWriter, ThreeItems) { MinidumpAnnotationListWriter list_writer; - for (size_t i = 0; i < base::size(kNames); ++i) { + for (size_t i = 0; i < std::size(kNames); ++i) { auto annotation = std::make_unique(); annotation->InitializeWithData(kNames[i], kTypes[i], kValues[i]); list_writer.AddObject(std::move(annotation)); diff --git a/minidump/minidump_byte_array_writer_test.cc b/minidump/minidump_byte_array_writer_test.cc index 526e38badf..8742ea4481 100644 --- a/minidump/minidump_byte_array_writer_test.cc +++ b/minidump/minidump_byte_array_writer_test.cc @@ -14,9 +14,9 @@ #include "minidump/minidump_byte_array_writer.h" +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -35,7 +35,7 @@ TEST(MinidumpByteArrayWriter, Write) { {}, }; - for (size_t i = 0; i < base::size(kTests); ++i) { + for (size_t i = 0; i < std::size(kTests); ++i) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i)); StringFile string_file; @@ -67,7 +67,7 @@ TEST(MinidumpByteArrayWriter, SetData) { {}, }; - for (size_t i = 0; i < base::size(kTests); ++i) { + for (size_t i = 0; i < std::size(kTests); ++i) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i)); crashpad::MinidumpByteArrayWriter writer; diff --git a/minidump/minidump_exception_writer_test.cc b/minidump/minidump_exception_writer_test.cc index 0243c175df..e09232fe7c 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -14,10 +14,10 @@ #include "minidump/minidump_exception_writer.h" +#include #include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "minidump/minidump_context_writer.h" @@ -86,7 +86,7 @@ void ExpectExceptionStream(const MINIDUMP_EXCEPTION_STREAM* expected, expected_exception.NumberParameters); EXPECT_EQ(observed->ExceptionRecord.__unusedAlignment, 0u); for (size_t index = 0; - index < base::size(observed_exception.ExceptionInformation); + index < std::size(observed_exception.ExceptionInformation); ++index) { EXPECT_EQ(observed_exception.ExceptionInformation[index], expected_exception.ExceptionInformation[index]); diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index e4be0b6dcb..75c8525c82 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -17,10 +17,10 @@ #include #include +#include #include #include -#include "base/cxx17_backports.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "minidump/minidump_stream_writer.h" @@ -156,7 +156,7 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { minidump_file.SetTimestamp(kTimestamp); static constexpr uint8_t kStreamData[] = "Hello World!"; - constexpr size_t kStreamSize = base::size(kStreamData); + constexpr size_t kStreamSize = std::size(kStreamData); constexpr MinidumpStreamType kStreamType = static_cast(0x4d); diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index 02a352fcea..0ca0652d08 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -14,9 +14,9 @@ #include "minidump/minidump_memory_writer.h" +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -342,7 +342,7 @@ TEST(MinidumpMemoryWriter, ExtraMemory) { TEST(MinidumpMemoryWriter, AddFromSnapshot) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[3] = {}; - uint8_t values[base::size(expect_memory_descriptors)] = {}; + uint8_t values[std::size(expect_memory_descriptors)] = {}; expect_memory_descriptors[0].StartOfMemoryRange = 0; expect_memory_descriptors[0].Memory.DataSize = 0x1000; @@ -358,7 +358,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { std::vector> memory_snapshots_owner; std::vector memory_snapshots; - for (size_t index = 0; index < base::size(expect_memory_descriptors); + for (size_t index = 0; index < std::size(expect_memory_descriptors); ++index) { memory_snapshots_owner.push_back(std::make_unique()); TestMemorySnapshot* memory_snapshot = memory_snapshots_owner.back().get(); @@ -397,7 +397,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { TEST(MinidumpMemoryWriter, CoalesceExplicitMultiple) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[4] = {}; - uint8_t values[base::size(expect_memory_descriptors)] = {}; + uint8_t values[std::size(expect_memory_descriptors)] = {}; expect_memory_descriptors[0].StartOfMemoryRange = 0; expect_memory_descriptors[0].Memory.DataSize = 1000; diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index 12c65b1a82..78847c1197 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -14,10 +14,10 @@ #include "minidump/minidump_misc_info_writer.h" +#include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" @@ -311,7 +311,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( AsU16CStr(misc_info_.TimeZone.StandardName), - base::size(misc_info_.TimeZone.StandardName), + std::size(misc_info_.TimeZone.StandardName), standard_name); misc_info_.TimeZone.StandardDate = standard_date; @@ -319,7 +319,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( AsU16CStr(misc_info_.TimeZone.DaylightName), - base::size(misc_info_.TimeZone.DaylightName), + std::size(misc_info_.TimeZone.DaylightName), daylight_name); misc_info_.TimeZone.DaylightDate = daylight_date; @@ -337,11 +337,11 @@ void MinidumpMiscInfoWriter::SetBuildString( internal::MinidumpWriterUtil::AssignUTF8ToUTF16( AsU16CStr(misc_info_.BuildString), - base::size(misc_info_.BuildString), + std::size(misc_info_.BuildString), build_string); internal::MinidumpWriterUtil::AssignUTF8ToUTF16( AsU16CStr(misc_info_.DbgBldStr), - base::size(misc_info_.DbgBldStr), + std::size(misc_info_.DbgBldStr), debug_build_string); } diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index f74d0bd5df..c983414187 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -16,10 +16,10 @@ #include +#include #include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -125,7 +125,7 @@ void ExpectMiscInfoEqual( SCOPED_TRACE("Standard"); ExpectNULPaddedString16Equal(AsU16CStr(expected->TimeZone.StandardName), AsU16CStr(observed->TimeZone.StandardName), - base::size(expected->TimeZone.StandardName)); + std::size(expected->TimeZone.StandardName)); ExpectSystemTimeEqual(&expected->TimeZone.StandardDate, &observed->TimeZone.StandardDate); EXPECT_EQ(observed->TimeZone.StandardBias, expected->TimeZone.StandardBias); @@ -134,7 +134,7 @@ void ExpectMiscInfoEqual( SCOPED_TRACE("Daylight"); ExpectNULPaddedString16Equal(AsU16CStr(expected->TimeZone.DaylightName), AsU16CStr(observed->TimeZone.DaylightName), - base::size(expected->TimeZone.DaylightName)); + std::size(expected->TimeZone.DaylightName)); ExpectSystemTimeEqual(&expected->TimeZone.DaylightDate, &observed->TimeZone.DaylightDate); EXPECT_EQ(observed->TimeZone.DaylightBias, expected->TimeZone.DaylightBias); @@ -152,13 +152,13 @@ void ExpectMiscInfoEqual( SCOPED_TRACE("BuildString"); ExpectNULPaddedString16Equal(AsU16CStr(expected->BuildString), AsU16CStr(observed->BuildString), - base::size(expected->BuildString)); + std::size(expected->BuildString)); } { SCOPED_TRACE("DbgBldStr"); ExpectNULPaddedString16Equal(AsU16CStr(expected->DbgBldStr), AsU16CStr(observed->DbgBldStr), - base::size(expected->DbgBldStr)); + std::size(expected->DbgBldStr)); } } @@ -181,7 +181,7 @@ void ExpectMiscInfoEqual( EXPECT_EQ(observed_misc_info.XStateData.EnabledFeatures, expected_misc_info.XStateData.EnabledFeatures); for (size_t feature_index = 0; - feature_index < base::size(observed_misc_info.XStateData.Features); + feature_index < std::size(observed_misc_info.XStateData.Features); ++feature_index) { SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index)); EXPECT_EQ(observed_misc_info.XStateData.Features[feature_index].Offset, @@ -408,7 +408,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::UTF8ToUTF16(Crbug1189439Cast(kStandardName)); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), - base::size(expected.TimeZone.StandardName)); + std::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kStandardDate, sizeof(expected.TimeZone.StandardDate)); @@ -417,7 +417,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::UTF8ToUTF16(Crbug1189439Cast(kDaylightName)); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), - base::size(expected.TimeZone.DaylightName)); + std::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kDaylightDate, sizeof(expected.TimeZone.DaylightDate)); @@ -436,9 +436,9 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { constexpr uint32_t kTimeZoneId = 2; constexpr int32_t kBias = 300; [[maybe_unused]] MINIDUMP_MISC_INFO_N tmp; - std::string standard_name(base::size(tmp.TimeZone.StandardName) + 1, 's'); + std::string standard_name(std::size(tmp.TimeZone.StandardName) + 1, 's'); constexpr int32_t kStandardBias = 0; - std::string daylight_name(base::size(tmp.TimeZone.DaylightName), 'd'); + std::string daylight_name(std::size(tmp.TimeZone.DaylightName), 'd'); constexpr int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to @@ -469,7 +469,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { std::u16string standard_name_utf16 = base::UTF8ToUTF16(standard_name); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), - base::size(expected.TimeZone.StandardName)); + std::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -477,7 +477,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { std::u16string daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), - base::size(expected.TimeZone.DaylightName)); + std::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -509,12 +509,12 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) { base::UTF8ToUTF16(Crbug1189439Cast(kBuildString)); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), - base::size(expected.BuildString)); + std::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDebugBuildString)); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), - base::size(expected.DbgBldStr)); + std::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -527,8 +527,8 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { auto misc_info_writer = std::make_unique(); [[maybe_unused]] MINIDUMP_MISC_INFO_N tmp; - std::string build_string(base::size(tmp.BuildString) + 1, 'B'); - std::string debug_build_string(base::size(tmp.DbgBldStr), 'D'); + std::string build_string(std::size(tmp.BuildString) + 1, 'B'); + std::string debug_build_string(std::size(tmp.DbgBldStr), 'D'); misc_info_writer->SetBuildString(build_string, debug_build_string); @@ -545,12 +545,12 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { std::u16string build_string_utf16 = base::UTF8ToUTF16(build_string); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), - base::size(expected.BuildString)); + std::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), - base::size(expected.DbgBldStr)); + std::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -691,7 +691,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::UTF8ToUTF16(Crbug1189439Cast(kStandardName)); c16lcpy(AsU16CStr(expected.TimeZone.StandardName), standard_name_utf16.c_str(), - base::size(expected.TimeZone.StandardName)); + std::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -700,7 +700,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::UTF8ToUTF16(Crbug1189439Cast(kDaylightName)); c16lcpy(AsU16CStr(expected.TimeZone.DaylightName), daylight_name_utf16.c_str(), - base::size(expected.TimeZone.DaylightName)); + std::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -709,12 +709,12 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::UTF8ToUTF16(Crbug1189439Cast(kBuildString)); c16lcpy(AsU16CStr(expected.BuildString), build_string_utf16.c_str(), - base::size(expected.BuildString)); + std::size(expected.BuildString)); std::u16string debug_build_string_utf16 = base::UTF8ToUTF16(Crbug1189439Cast(kDebugBuildString)); c16lcpy(AsU16CStr(expected.DbgBldStr), debug_build_string_utf16.c_str(), - base::size(expected.DbgBldStr)); + std::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -758,18 +758,18 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { expect_misc_info.TimeZone.Bias = 300; c16lcpy(AsU16CStr(expect_misc_info.TimeZone.StandardName), standard_time_name_utf16.c_str(), - base::size(expect_misc_info.TimeZone.StandardName)); + std::size(expect_misc_info.TimeZone.StandardName)); expect_misc_info.TimeZone.StandardBias = 0; c16lcpy(AsU16CStr(expect_misc_info.TimeZone.DaylightName), daylight_time_name_utf16.c_str(), - base::size(expect_misc_info.TimeZone.DaylightName)); + std::size(expect_misc_info.TimeZone.DaylightName)); expect_misc_info.TimeZone.DaylightBias = -60; c16lcpy(AsU16CStr(expect_misc_info.BuildString), build_string_utf16.c_str(), - base::size(expect_misc_info.BuildString)); + std::size(expect_misc_info.BuildString)); c16lcpy(AsU16CStr(expect_misc_info.DbgBldStr), debug_build_string_utf16.c_str(), - base::size(expect_misc_info.DbgBldStr)); + std::size(expect_misc_info.DbgBldStr)); const timeval kStartTime = { static_cast(expect_misc_info.ProcessCreateTime), 0}; diff --git a/minidump/minidump_module_crashpad_info_writer_test.cc b/minidump/minidump_module_crashpad_info_writer_test.cc index 613314b3f4..ba5c5f223d 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" #include "minidump/minidump_annotation_writer.h" #include "minidump/minidump_simple_string_dictionary_writer.h" @@ -155,9 +155,9 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { sizeof(MinidumpSimpleStringDictionaryEntry) + sizeof(MinidumpAnnotationList) + 2 + // padding sizeof(MinidumpAnnotation) + sizeof(MinidumpUTF8String) + - base::size(kEntry) + 2 + // padding - sizeof(MinidumpUTF8String) + base::size(kKey) + - sizeof(MinidumpUTF8String) + base::size(kValue) + + std::size(kEntry) + 2 + // padding + sizeof(MinidumpUTF8String) + std::size(kKey) + + sizeof(MinidumpUTF8String) + std::size(kValue) + sizeof(MinidumpUTF8String) + annotation.name.size() + 1 + sizeof(MinidumpByteArray) + annotation.value.size()); diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 131575fabc..e189d77e8e 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -793,10 +793,10 @@ void InitializeTestModuleSnapshotFromMinidumpModule( TEST(MinidumpModuleWriter, InitializeFromSnapshot) { MINIDUMP_MODULE expect_modules[3] = {}; - const char* module_paths[base::size(expect_modules)] = {}; - const char* module_pdbs[base::size(expect_modules)] = {}; - UUID uuids[base::size(expect_modules)] = {}; - uint32_t ages[base::size(expect_modules)] = {}; + const char* module_paths[std::size(expect_modules)] = {}; + const char* module_pdbs[std::size(expect_modules)] = {}; + UUID uuids[std::size(expect_modules)] = {}; + uint32_t ages[std::size(expect_modules)] = {}; expect_modules[0].BaseOfImage = 0x100101000; expect_modules[0].SizeOfImage = 0xf000; @@ -887,7 +887,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { std::vector> module_snapshots_owner; std::vector module_snapshots; - for (size_t index = 0; index < base::size(expect_modules); ++index) { + for (size_t index = 0; index < std::size(expect_modules); ++index) { module_snapshots_owner.push_back(std::make_unique()); TestModuleSnapshot* module_snapshot = module_snapshots_owner.back().get(); InitializeTestModuleSnapshotFromMinidumpModule(module_snapshot, diff --git a/minidump/minidump_rva_list_writer_test.cc b/minidump/minidump_rva_list_writer_test.cc index f99d9435c2..adfed11287 100644 --- a/minidump/minidump_rva_list_writer_test.cc +++ b/minidump/minidump_rva_list_writer_test.cc @@ -14,9 +14,9 @@ #include "minidump/minidump_rva_list_writer.h" +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -89,10 +89,10 @@ TEST(MinidumpRVAListWriter, ThreeChildren) { ASSERT_TRUE(list_writer.WriteEverything(&string_file)); const MinidumpRVAList* list = - MinidumpRVAListAtStart(string_file.string(), base::size(kValues)); + MinidumpRVAListAtStart(string_file.string(), std::size(kValues)); ASSERT_TRUE(list); - for (size_t index = 0; index < base::size(kValues); ++index) { + for (size_t index = 0; index < std::size(kValues); ++index) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, index)); const uint32_t* child = MinidumpWritableAtRVA( diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index 9609ade11f..f0cdb827f9 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -14,9 +14,9 @@ #include "minidump/minidump_string_writer.h" +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -66,16 +66,15 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { {4, "\360\220\204\202", 2, {0xd800, 0xdd02}}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", input %s", index, kTestData[index].input_string)); // Make sure that the expected output string with its NUL terminator fits in // the space provided. - ASSERT_EQ( - kTestData[index] - .output_string[base::size(kTestData[index].output_string) - 1], - 0); + ASSERT_EQ(kTestData[index] + .output_string[std::size(kTestData[index].output_string) - 1], + 0); string_file.Reset(); crashpad::internal::MinidumpUTF16StringWriter string_writer; @@ -112,7 +111,7 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { "\303\0\251", // NUL in middle of valid sequence }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", input %s", index, kTestData[index])); string_file.Reset(); @@ -173,7 +172,7 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { {4, "\360\220\204\202"}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", input %s", index, kTestData[index].string)); diff --git a/minidump/minidump_system_info_writer.cc b/minidump/minidump_system_info_writer.cc index 135010103b..bc9a5d65d3 100644 --- a/minidump/minidump_system_info_writer.cc +++ b/minidump/minidump_system_info_writer.cc @@ -16,8 +16,9 @@ #include +#include + #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/notreached.h" #include "minidump/minidump_string_writer.h" #include "snapshot/system_snapshot.h" @@ -235,7 +236,7 @@ void MinidumpSystemInfoWriter::SetCPUX86VendorString( sizeof(registers) == sizeof(system_info_.Cpu.X86CpuInfo.VendorId), "VendorId sizes must be equal"); - for (size_t index = 0; index < base::size(registers); ++index) { + for (size_t index = 0; index < std::size(registers); ++index) { memcpy(®isters[index], &vendor[index * sizeof(*registers)], sizeof(*registers)); diff --git a/minidump/minidump_thread_id_map_test.cc b/minidump/minidump_thread_id_map_test.cc index e972aebc9f..0883d9a554 100644 --- a/minidump/minidump_thread_id_map_test.cc +++ b/minidump/minidump_thread_id_map_test.cc @@ -16,9 +16,9 @@ #include +#include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" #include "snapshot/test/test_thread_snapshot.h" @@ -41,8 +41,7 @@ class MinidumpThreadIDMapTest : public testing::Test { // testing::Test: void SetUp() override { - for (size_t index = 0; index < base::size(test_thread_snapshots_); - ++index) { + for (size_t index = 0; index < std::size(test_thread_snapshots_); ++index) { thread_snapshots_.push_back(&test_thread_snapshots_[index]); } } @@ -63,7 +62,7 @@ class MinidumpThreadIDMapTest : public testing::Test { } void SetThreadID(size_t index, uint64_t thread_id) { - ASSERT_LT(index, base::size(test_thread_snapshots_)); + ASSERT_LT(index, std::size(test_thread_snapshots_)); test_thread_snapshots_[index].SetThreadID(thread_id); } diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc index 924c5c11ea..9b0e064ca6 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -14,11 +14,11 @@ #include "minidump/minidump_thread_writer.h" +#include #include #include #include "base/compiler_specific.h" -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -531,10 +531,10 @@ template void RunInitializeFromSnapshotTest(bool thread_id_collision) { using MinidumpContextType = typename Traits::MinidumpContextType; MINIDUMP_THREAD expect_threads[3] = {}; - uint64_t thread_ids[base::size(expect_threads)] = {}; - uint8_t memory_values[base::size(expect_threads)] = {}; - uint32_t context_seeds[base::size(expect_threads)] = {}; - MINIDUMP_MEMORY_DESCRIPTOR tebs[base::size(expect_threads)] = {}; + uint64_t thread_ids[std::size(expect_threads)] = {}; + uint8_t memory_values[std::size(expect_threads)] = {}; + uint32_t context_seeds[std::size(expect_threads)] = {}; + MINIDUMP_MEMORY_DESCRIPTOR tebs[std::size(expect_threads)] = {}; constexpr size_t kTebSize = 1024; @@ -590,7 +590,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) { std::vector> thread_snapshots_owner; std::vector thread_snapshots; - for (size_t index = 0; index < base::size(expect_threads); ++index) { + for (size_t index = 0; index < std::size(expect_threads); ++index) { thread_snapshots_owner.push_back(std::make_unique()); TestThreadSnapshot* thread_snapshot = thread_snapshots_owner.back().get(); diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index 8f69c9c16b..9bfba52e08 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h" @@ -245,7 +246,7 @@ bool MinidumpWritable::WritePaddingAndObject(FileWriterInterface* file_writer) { // The number of elements in kZeroes must be at least one less than the // maximum Alignment() ever encountered. static constexpr uint8_t kZeroes[kMaximumAlignment - 1] = {}; - DCHECK_LE(leading_pad_bytes_, base::size(kZeroes)); + DCHECK_LE(leading_pad_bytes_, std::size(kZeroes)); if (leading_pad_bytes_) { if (!file_writer->Write(&kZeroes, leading_pad_bytes_)) { diff --git a/minidump/test/minidump_context_test_util.cc b/minidump/test/minidump_context_test_util.cc index 446e5a1526..3836640c04 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -128,8 +129,7 @@ void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, context->ds = static_cast(value++); context->es = static_cast(value++); context->ss = static_cast(value++); - for (size_t index = 0; index < base::size(context->vector_register); - ++index) { + for (size_t index = 0; index < std::size(context->vector_register); ++index) { context->vector_register[index].lo = value++; context->vector_register[index].hi = value++; } @@ -152,7 +152,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < base::size(context->regs); ++index) { + for (size_t index = 0; index < std::size(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -163,7 +163,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < base::size(context->vfp); ++index) { + for (size_t index = 0; index < std::size(context->vfp); ++index) { context->vfp[index] = value++; } context->fpscr = value++; @@ -181,7 +181,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, uint32_t value = seed; - for (size_t index = 0; index < base::size(context->regs); ++index) { + for (size_t index = 0; index < std::size(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -190,7 +190,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < base::size(context->fpsimd); ++index) { + for (size_t index = 0; index < std::size(context->fpsimd); ++index) { context->fpsimd[index].lo = value++; context->fpsimd[index].hi = value++; } @@ -210,7 +210,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t value = seed; - for (size_t index = 0; index < base::size(context->regs); ++index) { + for (size_t index = 0; index < std::size(context->regs); ++index) { context->regs[index] = value++; } @@ -221,7 +221,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < base::size(context->fpregs.fregs); ++index) { + for (size_t index = 0; index < std::size(context->fpregs.fregs); ++index) { context->fpregs.fregs[index]._fp_fregs = static_cast(value++); } @@ -248,7 +248,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, uint64_t value = seed; - for (size_t index = 0; index < base::size(context->regs); ++index) { + for (size_t index = 0; index < std::size(context->regs); ++index) { context->regs[index] = value++; } @@ -259,7 +259,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < base::size(context->fpregs.dregs); ++index) { + for (size_t index = 0; index < std::size(context->fpregs.dregs); ++index) { context->fpregs.dregs[index] = static_cast(value++); } context->fpcsr = value++; @@ -294,33 +294,33 @@ void ExpectMinidumpContextFxsave(const FxsaveType* expected, EXPECT_EQ(observed->reserved_3, expected->reserved_3); EXPECT_EQ(observed->mxcsr, expected->mxcsr); EXPECT_EQ(observed->mxcsr_mask, expected->mxcsr_mask); - for (size_t st_mm_index = 0; st_mm_index < base::size(expected->st_mm); + for (size_t st_mm_index = 0; st_mm_index < std::size(expected->st_mm); ++st_mm_index) { SCOPED_TRACE(base::StringPrintf("st_mm_index %" PRIuS, st_mm_index)); EXPECT_EQ(BytesToHexString(observed->st_mm[st_mm_index].st, - base::size(observed->st_mm[st_mm_index].st)), + std::size(observed->st_mm[st_mm_index].st)), BytesToHexString(expected->st_mm[st_mm_index].st, - base::size(expected->st_mm[st_mm_index].st))); + std::size(expected->st_mm[st_mm_index].st))); EXPECT_EQ( BytesToHexString(observed->st_mm[st_mm_index].st_reserved, - base::size(observed->st_mm[st_mm_index].st_reserved)), + std::size(observed->st_mm[st_mm_index].st_reserved)), BytesToHexString(expected->st_mm[st_mm_index].st_reserved, - base::size(expected->st_mm[st_mm_index].st_reserved))); + std::size(expected->st_mm[st_mm_index].st_reserved))); } - for (size_t xmm_index = 0; xmm_index < base::size(expected->xmm); + for (size_t xmm_index = 0; xmm_index < std::size(expected->xmm); ++xmm_index) { EXPECT_EQ(BytesToHexString(observed->xmm[xmm_index], - base::size(observed->xmm[xmm_index])), + std::size(observed->xmm[xmm_index])), BytesToHexString(expected->xmm[xmm_index], - base::size(expected->xmm[xmm_index]))) + std::size(expected->xmm[xmm_index]))) << "xmm_index " << xmm_index; } EXPECT_EQ( - BytesToHexString(observed->reserved_4, base::size(observed->reserved_4)), - BytesToHexString(expected->reserved_4, base::size(expected->reserved_4))); + BytesToHexString(observed->reserved_4, std::size(observed->reserved_4)), + BytesToHexString(expected->reserved_4, std::size(expected->reserved_4))); EXPECT_EQ( - BytesToHexString(observed->available, base::size(observed->available)), - BytesToHexString(expected->available, base::size(expected->available))); + BytesToHexString(observed->available, std::size(observed->available)), + BytesToHexString(expected->available, std::size(expected->available))); } } // namespace @@ -345,11 +345,11 @@ void ExpectMinidumpContextX86( EXPECT_EQ(observed->fsave.fpu_cs, expected.fsave.fpu_cs); EXPECT_EQ(observed->fsave.fpu_dp, expected.fsave.fpu_dp); EXPECT_EQ(observed->fsave.fpu_ds, expected.fsave.fpu_ds); - for (size_t index = 0; index < base::size(expected.fsave.st); ++index) { + for (size_t index = 0; index < std::size(expected.fsave.st); ++index) { EXPECT_EQ(BytesToHexString(observed->fsave.st[index], - base::size(observed->fsave.st[index])), + std::size(observed->fsave.st[index])), BytesToHexString(expected.fsave.st[index], - base::size(expected.fsave.st[index]))) + std::size(expected.fsave.st[index]))) << "index " << index; } if (snapshot) { @@ -448,8 +448,7 @@ void ExpectMinidumpContextAMD64( ExpectMinidumpContextFxsave(&expected.fxsave, &observed->fxsave); - for (size_t index = 0; index < base::size(expected.vector_register); - ++index) { + for (size_t index = 0; index < std::size(expected.vector_register); ++index) { if (snapshot) { EXPECT_EQ(observed->vector_register[index].lo, 0u) << "index " << index; EXPECT_EQ(observed->vector_register[index].hi, 0u) << "index " << index; @@ -489,7 +488,7 @@ void ExpectMinidumpContextARM(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < base::size(expected.regs); ++index) { + for (size_t index = 0; index < std::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } EXPECT_EQ(observed->fp, expected.fp); @@ -500,10 +499,10 @@ void ExpectMinidumpContextARM(uint32_t expect_seed, EXPECT_EQ(observed->cpsr, expected.cpsr); EXPECT_EQ(observed->fpscr, expected.fpscr); - for (size_t index = 0; index < base::size(expected.vfp); ++index) { + for (size_t index = 0; index < std::size(expected.vfp); ++index) { EXPECT_EQ(observed->vfp[index], expected.vfp[index]); } - for (size_t index = 0; index < base::size(expected.extra); ++index) { + for (size_t index = 0; index < std::size(expected.extra); ++index) { EXPECT_EQ(observed->extra[index], snapshot ? 0 : expected.extra[index]); } } @@ -516,14 +515,14 @@ void ExpectMinidumpContextARM64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < base::size(expected.regs); ++index) { + for (size_t index = 0; index < std::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } EXPECT_EQ(observed->cpsr, expected.cpsr); EXPECT_EQ(observed->fpsr, expected.fpsr); EXPECT_EQ(observed->fpcr, expected.fpcr); - for (size_t index = 0; index < base::size(expected.fpsimd); ++index) { + for (size_t index = 0; index < std::size(expected.fpsimd); ++index) { EXPECT_EQ(observed->fpsimd[index].lo, expected.fpsimd[index].lo); EXPECT_EQ(observed->fpsimd[index].hi, expected.fpsimd[index].hi); } @@ -537,7 +536,7 @@ void ExpectMinidumpContextMIPS(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < base::size(expected.regs); ++index) { + for (size_t index = 0; index < std::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -548,7 +547,7 @@ void ExpectMinidumpContextMIPS(uint32_t expect_seed, EXPECT_EQ(observed->status, expected.status); EXPECT_EQ(observed->cause, expected.cause); - for (size_t index = 0; index < base::size(expected.fpregs.fregs); ++index) { + for (size_t index = 0; index < std::size(expected.fpregs.fregs); ++index) { EXPECT_EQ(observed->fpregs.fregs[index]._fp_fregs, expected.fpregs.fregs[index]._fp_fregs); } @@ -570,7 +569,7 @@ void ExpectMinidumpContextMIPS64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < base::size(expected.regs); ++index) { + for (size_t index = 0; index < std::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -581,7 +580,7 @@ void ExpectMinidumpContextMIPS64(uint32_t expect_seed, EXPECT_EQ(observed->status, expected.status); EXPECT_EQ(observed->cause, expected.cause); - for (size_t index = 0; index < base::size(expected.fpregs.dregs); ++index) { + for (size_t index = 0; index < std::size(expected.fpregs.dregs); ++index) { EXPECT_EQ(observed->fpregs.dregs[index], expected.fpregs.dregs[index]); } EXPECT_EQ(observed->fpcsr, expected.fpcsr); diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index 5c7ded46b1..06d9258133 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -16,10 +16,10 @@ #include +#include #include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "snapshot/memory_snapshot.h" @@ -99,17 +99,17 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, #elif defined(ARCH_CPU_ARM_FAMILY) if (context.architecture == kCPUArchitectureARM64) { MaybeCaptureMemoryAround(delegate, context.arm64->pc); - for (size_t i = 0; i < base::size(context.arm64->regs); ++i) { + for (size_t i = 0; i < std::size(context.arm64->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm64->regs[i]); } } else { MaybeCaptureMemoryAround(delegate, context.arm->pc); - for (size_t i = 0; i < base::size(context.arm->regs); ++i) { + for (size_t i = 0; i < std::size(context.arm->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm->regs[i]); } } #elif defined(ARCH_CPU_MIPS_FAMILY) - for (size_t i = 0; i < base::size(context.mipsel->regs); ++i) { + for (size_t i = 0; i < std::size(context.mipsel->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]); } #else diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc index 643ad80f01..2e29f70398 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/notreached.h" #include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" @@ -58,7 +59,7 @@ void CPUContextX86::FxsaveToFsave(const Fxsave& fxsave, Fsave* fsave) { fsave->reserved_4 = 0; static_assert(ArraySize(fsave->st) == ArraySize(fxsave.st_mm), "FPU stack registers must be equivalent"); - for (size_t index = 0; index < base::size(fsave->st); ++index) { + for (size_t index = 0; index < std::size(fsave->st); ++index) { memcpy(fsave->st[index], fxsave.st_mm[index].st, sizeof(fsave->st[index])); } } @@ -80,7 +81,7 @@ void CPUContextX86::FsaveToFxsave(const Fsave& fsave, Fxsave* fxsave) { fxsave->mxcsr_mask = 0; static_assert(ArraySize(fxsave->st_mm) == ArraySize(fsave.st), "FPU stack registers must be equivalent"); - for (size_t index = 0; index < base::size(fsave.st); ++index) { + for (size_t index = 0; index < std::size(fsave.st); ++index) { memcpy(fxsave->st_mm[index].st, fsave.st[index], sizeof(fsave.st[index])); memset(fxsave->st_mm[index].st_reserved, 0, diff --git a/snapshot/cpu_context_test.cc b/snapshot/cpu_context_test.cc index b1340d6ee1..019c7694f5 100644 --- a/snapshot/cpu_context_test.cc +++ b/snapshot/cpu_context_test.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" #include "test/hex_string.h" @@ -124,7 +125,7 @@ TEST(CPUContextX86, FxsaveToFsave) { &fxsave.st_mm[6].st, kExponentAllZero, false, kFractionAllZero); SetX87Register( &fxsave.st_mm[7].st, kExponentNormal, true, kFractionNormal); // valid - for (size_t index = 0; index < base::size(fxsave.st_mm); ++index) { + for (size_t index = 0; index < std::size(fxsave.st_mm); ++index) { memset(&fxsave.st_mm[index].st_reserved, 0x5a, sizeof(fxsave.st_mm[index].st_reserved)); @@ -148,10 +149,10 @@ TEST(CPUContextX86, FxsaveToFsave) { EXPECT_EQ(fsave.fpu_dp, fxsave.fpu_dp); EXPECT_EQ(fsave.fpu_ds, fxsave.fpu_ds); EXPECT_EQ(fsave.reserved_4, 0); - for (size_t index = 0; index < base::size(fsave.st); ++index) { - EXPECT_EQ(BytesToHexString(fsave.st[index], base::size(fsave.st[index])), + for (size_t index = 0; index < std::size(fsave.st); ++index) { + EXPECT_EQ(BytesToHexString(fsave.st[index], std::size(fsave.st[index])), BytesToHexString(fxsave.st_mm[index].st, - base::size(fxsave.st_mm[index].st))) + std::size(fxsave.st_mm[index].st))) << "index " << index; } } @@ -204,14 +205,14 @@ TEST(CPUContextX86, FsaveToFxsave) { EXPECT_EQ(fxsave.reserved_3, 0); EXPECT_EQ(fxsave.mxcsr, 0u); EXPECT_EQ(fxsave.mxcsr_mask, 0u); - for (size_t index = 0; index < base::size(fxsave.st_mm); ++index) { + for (size_t index = 0; index < std::size(fxsave.st_mm); ++index) { EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st, - base::size(fxsave.st_mm[index].st)), - BytesToHexString(fsave.st[index], base::size(fsave.st[index]))) + std::size(fxsave.st_mm[index].st)), + BytesToHexString(fsave.st[index], std::size(fsave.st[index]))) << "index " << index; EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st_reserved, - base::size(fxsave.st_mm[index].st_reserved)), - std::string(base::size(fxsave.st_mm[index].st_reserved) * 2, '0')) + std::size(fxsave.st_mm[index].st_reserved)), + std::string(std::size(fxsave.st_mm[index].st_reserved) * 2, '0')) << "index " << index; } size_t unused_len = sizeof(fxsave) - offsetof(decltype(fxsave), xmm); @@ -318,7 +319,7 @@ TEST(CPUContextX86, FxsaveToFsaveTagWord) { // In this set, everything is valid. fsw = 0 << 11; // top = 0: logical 0-7 maps to physical 0-7 fxsave_tag = 0xff; // nothing empty - for (size_t index = 0; index < base::size(st_mm); ++index) { + for (size_t index = 0; index < std::size(st_mm); ++index) { SetX87OrMMXRegister(&st_mm[index], kExponentNormal, true, kFractionAllZero); } EXPECT_EQ(CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm), 0); diff --git a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc index a5885b06c6..8d7f9b867e 100644 --- a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc @@ -14,8 +14,9 @@ #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" +#include + #include "base/check_op.h" -#include "base/cxx17_backports.h" namespace crashpad { namespace internal { @@ -50,7 +51,7 @@ uint32_t MmuFlagsToProtectFlags(zx_vm_option_t flags) { const uint32_t index = flags & (ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE); - DCHECK_LT(index, base::size(mapping)); + DCHECK_LT(index, std::size(mapping)); const uint32_t protect_flags = mapping[index]; DCHECK_NE(protect_flags, 0u); diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index f5a8aea750..362be5bd46 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -20,7 +20,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" #include "test/multiprocess_exec.h" #include "test/test_paths.h" @@ -35,7 +36,7 @@ TEST(ProcessReaderFuchsia, SelfBasic) { ASSERT_TRUE(process_reader.Initialize(*zx::process::self())); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[base::size(kTestMemory)]; + char buffer[std::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); diff --git a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc index 9389868ba0..874f159054 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" +#include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include #include -#include "base/cxx17_backports.h" +#include + #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "snapshot/fuchsia/process_snapshot_fuchsia.h" +#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" #include "test/multiprocess_exec.h" #include "util/fuchsia/koid_utilities.h" #include "util/fuchsia/scoped_task_suspend.h" @@ -111,8 +112,8 @@ class AddressSpaceTest : public MultiprocessExec { private: void MultiprocessParent() override { - uintptr_t test_addresses[base::size(kTestMappingPermAndSizes)]; - for (size_t i = 0; i < base::size(test_addresses); ++i) { + uintptr_t test_addresses[std::size(kTestMappingPermAndSizes)]; + for (size_t i = 0; i < std::size(test_addresses); ++i) { ASSERT_TRUE(ReadFileExactly( ReadPipeHandle(), &test_addresses[i], sizeof(test_addresses[i]))); } @@ -122,7 +123,7 @@ class AddressSpaceTest : public MultiprocessExec { ProcessSnapshotFuchsia process_snapshot; ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess())); - for (size_t i = 0; i < base::size(test_addresses); ++i) { + for (size_t i = 0; i < std::size(test_addresses); ++i) { const auto& t = kTestMappingPermAndSizes[i]; EXPECT_TRUE(HasSingleMatchingMapping(process_snapshot.MemoryMap(), test_addresses[i], diff --git a/snapshot/linux/exception_snapshot_linux_test.cc b/snapshot/linux/exception_snapshot_linux_test.cc index 91be497a77..a045f36594 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -21,8 +21,9 @@ #include #include +#include + #include "base/bit_cast.h" -#include "base/cxx17_backports.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "snapshot/cpu_architecture.h" @@ -170,7 +171,7 @@ void InitializeContext(NativeCPUContext* context) { test_context->vfp.head.magic = VFP_MAGIC; test_context->vfp.head.size = sizeof(test_context->vfp); memset(&test_context->vfp.context, 'v', sizeof(test_context->vfp.context)); - for (size_t reg = 0; reg < base::size(test_context->vfp.context.vfp.fpregs); + for (size_t reg = 0; reg < std::size(test_context->vfp.context.vfp.fpregs); ++reg) { test_context->vfp.context.vfp.fpregs[reg] = reg; } @@ -218,7 +219,7 @@ struct TestCoprocessorContext { void InitializeContext(NativeCPUContext* context) { memset(context, 'x', sizeof(*context)); - for (size_t index = 0; index < base::size(context->uc_mcontext.regs); + for (size_t index = 0; index < std::size(context->uc_mcontext.regs); ++index) { context->uc_mcontext.regs[index] = index; } @@ -237,7 +238,7 @@ void InitializeContext(NativeCPUContext* context) { test_context->fpsimd.head.size = sizeof(test_context->fpsimd); test_context->fpsimd.fpsr = 1; test_context->fpsimd.fpcr = 2; - for (size_t reg = 0; reg < base::size(test_context->fpsimd.vregs); ++reg) { + for (size_t reg = 0; reg < std::size(test_context->fpsimd.vregs); ++reg) { test_context->fpsimd.vregs[reg] = reg; } @@ -270,7 +271,7 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { using NativeCPUContext = ucontext_t; void InitializeContext(NativeCPUContext* context) { - for (size_t reg = 0; reg < base::size(context->uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < std::size(context->uc_mcontext.gregs); ++reg) { context->uc_mcontext.gregs[reg] = reg; } memset(&context->uc_mcontext.fpregs, 44, sizeof(context->uc_mcontext.fpregs)); @@ -285,7 +286,7 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { #define CPU_ARCH_NAME mips64 #endif - for (size_t reg = 0; reg < base::size(expected.uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < std::size(expected.uc_mcontext.gregs); ++reg) { EXPECT_EQ(actual.CPU_ARCH_NAME->regs[reg], expected.uc_mcontext.gregs[reg]); } diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index 8cc90a0e88..81b3d6ec67 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -26,12 +26,12 @@ #include #include +#include #include #include #include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/memory/free_deleter.h" #include "base/strings/stringprintf.h" @@ -88,7 +88,7 @@ TEST(ProcessReaderLinux, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[base::size(kTestMemory)]; + char buffer[std::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast(kTestMemory), sizeof(kTestMemory), diff --git a/snapshot/mac/mach_o_image_reader.cc b/snapshot/mac/mach_o_image_reader.cc index 4e66f3db8c..5c5bcb00f2 100644 --- a/snapshot/mac/mach_o_image_reader.cc +++ b/snapshot/mac/mach_o_image_reader.cc @@ -18,10 +18,10 @@ #include #include +#include #include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" @@ -183,7 +183,7 @@ bool MachOImageReader::Initialize(ProcessReaderMac* process_reader, // This vector is parallel to the kLoadCommandReaders array, and tracks // whether a singleton load command matching the |command| field has been // found yet. - std::vector singleton_indices(base::size(kLoadCommandReaders), + std::vector singleton_indices(std::size(kLoadCommandReaders), kInvalidSegmentIndex); size_t offset = mach_header.Size(); @@ -236,8 +236,7 @@ bool MachOImageReader::Initialize(ProcessReaderMac* process_reader, return false; } - for (size_t reader_index = 0; - reader_index < base::size(kLoadCommandReaders); + for (size_t reader_index = 0; reader_index < std::size(kLoadCommandReaders); ++reader_index) { if (load_command.cmd != kLoadCommandReaders[reader_index].command) { continue; diff --git a/snapshot/mac/mach_o_image_segment_reader_test.cc b/snapshot/mac/mach_o_image_segment_reader_test.cc index f89b475f50..38e55dfa1f 100644 --- a/snapshot/mac/mach_o_image_segment_reader_test.cc +++ b/snapshot/mac/mach_o_image_segment_reader_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -63,7 +64,7 @@ TEST(MachOImageSegmentReader, SegmentNameString) { SEG_IMPORT, }; - for (size_t index = 0; index < base::size(kSegmentTestData); ++index) { + for (size_t index = 0; index < std::size(kSegmentTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SegmentNameString(kSegmentTestData[index]), kSegmentTestData[index]) @@ -106,7 +107,7 @@ TEST(MachOImageSegmentReader, SectionNameString) { SECT_ICON_TIFF, }; - for (size_t index = 0; index < base::size(kSectionTestData); ++index) { + for (size_t index = 0; index < std::size(kSectionTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SectionNameString(kSectionTestData[index]), kSectionTestData[index]) @@ -169,7 +170,7 @@ TEST(MachOImageSegmentReader, SegmentAndSectionNameString) { {SEG_IMPORT, "", "__IMPORT,"}, }; - for (size_t index = 0; index < base::size(kSegmentAndSectionTestData); + for (size_t index = 0; index < std::size(kSegmentAndSectionTestData); ++index) { const auto& test = kSegmentAndSectionTestData[index]; EXPECT_EQ(MachOImageSegmentReader::SegmentAndSectionNameString( diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 6b4e108b99..8868950845 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -25,11 +25,11 @@ #include #include +#include #include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/posix/eintr_wrapper.h" @@ -68,7 +68,7 @@ TEST(ProcessReaderMac, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[base::size(kTestMemory)]; + char buffer[std::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( FromPointerCast(kTestMemory), sizeof(kTestMemory), @@ -702,11 +702,11 @@ class ScopedOpenCLNoOpKernel { const size_t source_lengths[] = { strlen(sources[0]), }; - static_assert(base::size(sources) == base::size(source_lengths), + static_assert(std::size(sources) == std::size(source_lengths), "arrays must be parallel"); program_ = clCreateProgramWithSource( - context_, base::size(sources), sources, source_lengths, &rv); + context_, std::size(sources), sources, source_lengths, &rv); ASSERT_EQ(rv, CL_SUCCESS) << "clCreateProgramWithSource"; rv = clBuildProgram( diff --git a/snapshot/mac/process_types.cc b/snapshot/mac/process_types.cc index 3d4e059020..c91b697d12 100644 --- a/snapshot/mac/process_types.cc +++ b/snapshot/mac/process_types.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "snapshot/mac/process_types/internal.h" #include "util/process/process_memory_mac.h" @@ -74,7 +74,7 @@ using UInt64Array4 = uint64_t[4]; template <> inline void Assign(UInt64Array4* destination, const UInt32Array4& source) { - for (size_t index = 0; index < base::size(source); ++index) { + for (size_t index = 0; index < std::size(source); ++index) { (*destination)[index] = source[index]; } } diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 06c13001d0..5c6dec98d2 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -12,21 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "snapshot/mac/process_types.h" - #include #include #include #include +#include #include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/numerics/safe_math.h" #include "base/strings/stringprintf.h" +#include "snapshot/mac/process_types.h" #include "snapshot/mac/process_types/internal.h" #include "util/mac/mac_util.h" #include "util/process/process_memory_mac.h" @@ -150,8 +149,8 @@ size_t dyld_all_image_infos::ExpectedSizeForVersion( sizeof(dyld_all_image_infos), // 18 }; - if (version >= base::size(kSizeForVersion)) { - return kSizeForVersion[base::size(kSizeForVersion) - 1]; + if (version >= std::size(kSizeForVersion)) { + return kSizeForVersion[std::size(kSizeForVersion) - 1]; } static_assert(std::is_unsigned::value, diff --git a/snapshot/mac/process_types_test.cc b/snapshot/mac/process_types_test.cc index 90f5c1f679..2946dc25c3 100644 --- a/snapshot/mac/process_types_test.cc +++ b/snapshot/mac/process_types_test.cc @@ -18,10 +18,10 @@ #include #include +#include #include #include -#include "base/cxx17_backports.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -172,7 +172,7 @@ TEST(ProcessTypes, DyldImagesSelf) { {16, kUnsupported, 328}, {17, kUnsupported, 368}, }; - for (size_t index = 0; index < base::size(kVersionsAndSizes); ++index) { + for (size_t index = 0; index < std::size(kVersionsAndSizes); ++index) { uint32_t version = kVersionsAndSizes[index].version; SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version)); @@ -325,7 +325,7 @@ TEST(ProcessTypes, DyldImagesSelf) { self_image_infos->sharedCacheBaseAddress); EXPECT_EQ(proctype_image_infos.dyldPath, reinterpret_cast(self_image_infos->dyldPath)); - for (size_t index = 0; index < base::size(self_image_infos->notifyPorts); + for (size_t index = 0; index < std::size(self_image_infos->notifyPorts); ++index) { EXPECT_EQ(proctype_image_infos.notifyPorts[index], self_image_infos->notifyPorts[index]) @@ -345,7 +345,7 @@ TEST(ProcessTypes, DyldImagesSelf) { // process_types version. It’s difficult to compare the reserved fields in // these older SDKs, so only do it where the declarations match. if (proctype_image_infos.version >= 14) { - for (size_t index = 0; index < base::size(proctype_image_infos.reserved); + for (size_t index = 0; index < std::size(proctype_image_infos.reserved); ++index) { EXPECT_EQ(proctype_image_infos.reserved[index], implicit_cast(self_image_infos->reserved[index])) diff --git a/snapshot/minidump/minidump_context_converter.cc b/snapshot/minidump/minidump_context_converter.cc index 981f34c974..5e94ca2cbc 100644 --- a/snapshot/minidump/minidump_context_converter.cc +++ b/snapshot/minidump/minidump_context_converter.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "minidump/minidump_context.h" @@ -147,7 +148,7 @@ bool MinidumpContextConverter::Initialize( return false; } - for (size_t i = 0; i < base::size(src->regs); i++) { + for (size_t i = 0; i < std::size(src->regs); i++) { context_.arm->regs[i] = src->regs[i]; } @@ -159,7 +160,7 @@ bool MinidumpContextConverter::Initialize( context_.arm->cpsr = src->cpsr; context_.arm->vfp_regs.fpscr = src->fpscr; - for (size_t i = 0; i < base::size(src->vfp); i++) { + for (size_t i = 0; i < std::size(src->vfp); i++) { context_.arm->vfp_regs.vfp[i] = src->vfp[i]; } @@ -179,14 +180,14 @@ bool MinidumpContextConverter::Initialize( return false; } - for (size_t i = 0; i < base::size(src->regs); i++) { + for (size_t i = 0; i < std::size(src->regs); i++) { context_.arm64->regs[i] = src->regs[i]; } context_.arm64->regs[29] = src->fp; context_.arm64->regs[30] = src->lr; - for (size_t i = 0; i < base::size(src->fpsimd); i++) { + for (size_t i = 0; i < std::size(src->fpsimd); i++) { context_.arm64->fpsimd[i] = src->fpsimd[i]; } @@ -208,7 +209,7 @@ bool MinidumpContextConverter::Initialize( return false; } - for (size_t i = 0; i < base::size(src->regs); i++) { + for (size_t i = 0; i < std::size(src->regs); i++) { context_.mipsel->regs[i] = src->regs[i]; } @@ -216,7 +217,7 @@ bool MinidumpContextConverter::Initialize( context_.mipsel->mdlo = static_cast(src->mdlo); context_.mipsel->dsp_control = src->dsp_control; - for (size_t i = 0; i < base::size(src->hi); i++) { + for (size_t i = 0; i < std::size(src->hi); i++) { context_.mipsel->hi[i] = src->hi[i]; context_.mipsel->lo[i] = src->lo[i]; } @@ -244,7 +245,7 @@ bool MinidumpContextConverter::Initialize( return false; } - for (size_t i = 0; i < base::size(src->regs); i++) { + for (size_t i = 0; i < std::size(src->regs); i++) { context_.mips64->regs[i] = src->regs[i]; } @@ -252,7 +253,7 @@ bool MinidumpContextConverter::Initialize( context_.mips64->mdlo = src->mdlo; context_.mips64->dsp_control = src->dsp_control; - for (size_t i = 0; i < base::size(src->hi); i++) { + for (size_t i = 0; i < std::size(src->hi); i++) { context_.mips64->hi[i] = src->hi[i]; context_.mips64->lo[i] = src->lo[i]; } diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 3c5dcf6c23..ded561bf1c 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -19,9 +19,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/numerics/safe_math.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" @@ -980,27 +980,27 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { minidump_context.fxsave.fpu_ip_64 = 42; minidump_context.fxsave.fpu_dp_64 = 43; - for (size_t i = 0; i < base::size(minidump_context.vector_register); i++) { + for (size_t i = 0; i < std::size(minidump_context.vector_register); i++) { minidump_context.vector_register[i].lo = i * 2 + 44; minidump_context.vector_register[i].hi = i * 2 + 45; } - for (uint8_t i = 0; i < base::size(minidump_context.fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < std::size(minidump_context.fxsave.reserved_4); i++) { minidump_context.fxsave.reserved_4[i] = i * 2 + 115; minidump_context.fxsave.available[i] = i * 2 + 116; } - for (size_t i = 0; i < base::size(minidump_context.fxsave.st_mm); i++) { + for (size_t i = 0; i < std::size(minidump_context.fxsave.st_mm); i++) { for (uint8_t j = 0; - j < base::size(minidump_context.fxsave.st_mm[0].mm_value); + j < std::size(minidump_context.fxsave.st_mm[0].mm_value); j++) { minidump_context.fxsave.st_mm[i].mm_value[j] = j + 1; minidump_context.fxsave.st_mm[i].mm_reserved[j] = j + 1; } } - for (size_t i = 0; i < base::size(minidump_context.fxsave.xmm); i++) { - for (uint8_t j = 0; j < base::size(minidump_context.fxsave.xmm[0]); j++) { + for (size_t i = 0; i < std::size(minidump_context.fxsave.xmm); i++) { + for (uint8_t j = 0; j < std::size(minidump_context.fxsave.xmm[0]); j++) { minidump_context.fxsave.xmm[i][j] = j + 1; } } @@ -1083,20 +1083,20 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { EXPECT_EQ(ctx->fxsave.fpu_ip_64, 42U); EXPECT_EQ(ctx->fxsave.fpu_dp_64, 43U); - for (uint8_t i = 0; i < base::size(ctx->fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < std::size(ctx->fxsave.reserved_4); i++) { EXPECT_EQ(ctx->fxsave.reserved_4[i], i * 2 + 115); EXPECT_EQ(ctx->fxsave.available[i], i * 2 + 116); } - for (size_t i = 0; i < base::size(ctx->fxsave.st_mm); i++) { - for (uint8_t j = 0; j < base::size(ctx->fxsave.st_mm[0].mm_value); j++) { + for (size_t i = 0; i < std::size(ctx->fxsave.st_mm); i++) { + for (uint8_t j = 0; j < std::size(ctx->fxsave.st_mm[0].mm_value); j++) { EXPECT_EQ(ctx->fxsave.st_mm[i].mm_value[j], j + 1); EXPECT_EQ(ctx->fxsave.st_mm[i].mm_reserved[j], j + 1); } } - for (size_t i = 0; i < base::size(ctx->fxsave.xmm); i++) { - for (uint8_t j = 0; j < base::size(ctx->fxsave.xmm[0]); j++) { + for (size_t i = 0; i < std::size(ctx->fxsave.xmm); i++) { + for (uint8_t j = 0; j < std::size(ctx->fxsave.xmm[0]); j++) { EXPECT_EQ(ctx->fxsave.xmm[i][j], j + 1); } } diff --git a/snapshot/posix/timezone.cc b/snapshot/posix/timezone.cc index e4b52081d1..3591157e82 100644 --- a/snapshot/posix/timezone.cc +++ b/snapshot/posix/timezone.cc @@ -17,8 +17,9 @@ #include #include +#include + #include "base/check.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "build/build_config.h" @@ -61,8 +62,7 @@ void TimeZone(const timeval& snapshot_time, static constexpr int kMonthDeltas[] = {0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12}; - for (size_t index = 0; - index < base::size(kMonthDeltas) && !found_transition; + for (size_t index = 0; index < std::size(kMonthDeltas) && !found_transition; ++index) { // Look at a day of each month at local noon. Set tm_isdst to -1 to avoid // giving mktime() any hints about whether to consider daylight saving diff --git a/snapshot/posix/timezone_test.cc b/snapshot/posix/timezone_test.cc index 6a343767e3..990a063ebc 100644 --- a/snapshot/posix/timezone_test.cc +++ b/snapshot/posix/timezone_test.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/errors.h" @@ -154,7 +154,7 @@ TEST(TimeZone, Basic) { {"UTC", false, 0, 0, "UTC", "UTC"}, }; - for (size_t index = 0; index < base::size(kTestTimeZones); ++index) { + for (size_t index = 0; index < std::size(kTestTimeZones); ++index) { const auto& test_time_zone = kTestTimeZones[index]; const char* tz = test_time_zone.tz; SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz)); diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index f6ef1efa5f..306f2df26a 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/notreached.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -101,7 +102,7 @@ void ChildTestFunction() { static StringAnnotation<32> non_allowed_annotation(kNonAllowedAnnotationName); non_allowed_annotation.Set(kNonAllowedAnnotationValue); - char string_data[base::size(kSensitiveStackData)]; + char string_data[std::size(kSensitiveStackData)]; strcpy(string_data, kSensitiveStackData); void (*code_pointer)(void) = ChildTestFunction; diff --git a/snapshot/sanitized/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc index 933bc923e7..65b01f0858 100644 --- a/snapshot/sanitized/sanitization_information_test.cc +++ b/snapshot/sanitized/sanitization_information_test.cc @@ -14,7 +14,8 @@ #include "snapshot/sanitized/sanitization_information.h" -#include "base/cxx17_backports.h" +#include + #include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/from_pointer_cast.h" @@ -66,7 +67,7 @@ const char* const kNonEmptyAllowedAnnotations[] = {"string1", TEST_F(AllowedAnnotationsTest, NonEmptyAllowedAnnotations) { ASSERT_TRUE(DoReadAllowedAnnotations(kNonEmptyAllowedAnnotations)); ASSERT_EQ(allowed_annotations_.size(), - base::size(kNonEmptyAllowedAnnotations) - 1); + std::size(kNonEmptyAllowedAnnotations) - 1); for (size_t index = 0; index < allowed_annotations_.size(); ++index) { EXPECT_EQ(allowed_annotations_[index], kNonEmptyAllowedAnnotations[index]); } diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 4923d4c4f9..75d9c5a1fa 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -17,7 +17,7 @@ #include #include -#include "base/cxx17_backports.h" +#include namespace crashpad { namespace test { @@ -44,28 +44,28 @@ void InitializeCPUContextFxsave(FxsaveType* fxsave, uint32_t* seed) { fxsave->reserved_3 = static_cast(value++); fxsave->mxcsr = value++; fxsave->mxcsr_mask = value++; - for (size_t st_mm_index = 0; st_mm_index < base::size(fxsave->st_mm); + for (size_t st_mm_index = 0; st_mm_index < std::size(fxsave->st_mm); ++st_mm_index) { - for (size_t byte = 0; byte < base::size(fxsave->st_mm[st_mm_index].st); + for (size_t byte = 0; byte < std::size(fxsave->st_mm[st_mm_index].st); ++byte) { fxsave->st_mm[st_mm_index].st[byte] = static_cast(value++); } for (size_t byte = 0; - byte < base::size(fxsave->st_mm[st_mm_index].st_reserved); + byte < std::size(fxsave->st_mm[st_mm_index].st_reserved); ++byte) { fxsave->st_mm[st_mm_index].st_reserved[byte] = static_cast(value); } } - for (size_t xmm_index = 0; xmm_index < base::size(fxsave->xmm); ++xmm_index) { - for (size_t byte = 0; byte < base::size(fxsave->xmm[xmm_index]); ++byte) { + for (size_t xmm_index = 0; xmm_index < std::size(fxsave->xmm); ++xmm_index) { + for (size_t byte = 0; byte < std::size(fxsave->xmm[xmm_index]); ++byte) { fxsave->xmm[xmm_index][byte] = static_cast(value++); } } - for (size_t byte = 0; byte < base::size(fxsave->reserved_4); ++byte) { + for (size_t byte = 0; byte < std::size(fxsave->reserved_4); ++byte) { fxsave->reserved_4[byte] = static_cast(value++); } - for (size_t byte = 0; byte < base::size(fxsave->available); ++byte) { + for (size_t byte = 0; byte < std::size(fxsave->available); ++byte) { fxsave->available[byte] = static_cast(value++); } @@ -174,7 +174,7 @@ void InitializeCPUContextARM(CPUContext* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < base::size(arm->regs); ++index) { + for (size_t index = 0; index < std::size(arm->regs); ++index) { arm->regs[index] = value++; } arm->fp = value++; @@ -185,7 +185,7 @@ void InitializeCPUContextARM(CPUContext* context, uint32_t seed) { arm->pc = value++; arm->cpsr = value++; - for (size_t index = 0; index < base::size(arm->vfp_regs.vfp); ++index) { + for (size_t index = 0; index < std::size(arm->vfp_regs.vfp); ++index) { arm->vfp_regs.vfp[index] = value++; } arm->vfp_regs.fpscr = value++; @@ -205,14 +205,14 @@ void InitializeCPUContextARM64(CPUContext* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < base::size(arm64->regs); ++index) { + for (size_t index = 0; index < std::size(arm64->regs); ++index) { arm64->regs[index] = value++; } arm64->sp = value++; arm64->pc = value++; arm64->spsr = value++; - for (size_t index = 0; index < base::size(arm64->fpsimd); ++index) { + for (size_t index = 0; index < std::size(arm64->fpsimd); ++index) { arm64->fpsimd[index].lo = value++; arm64->fpsimd[index].hi = value++; } @@ -231,7 +231,7 @@ void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < base::size(mipsel->regs); ++index) { + for (size_t index = 0; index < std::size(mipsel->regs); ++index) { mipsel->regs[index] = value++; } @@ -242,7 +242,7 @@ void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed) { mipsel->cp0_status = value++; mipsel->cp0_cause = value++; - for (size_t index = 0; index < base::size(mipsel->fpregs.fregs); ++index) { + for (size_t index = 0; index < std::size(mipsel->fpregs.fregs); ++index) { mipsel->fpregs.fregs[index]._fp_fregs = static_cast(value++); } @@ -267,7 +267,7 @@ void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) { uint64_t value = seed; - for (size_t index = 0; index < base::size(mips64->regs); ++index) { + for (size_t index = 0; index < std::size(mips64->regs); ++index) { mips64->regs[index] = value++; } @@ -278,7 +278,7 @@ void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) { mips64->cp0_status = value++; mips64->cp0_cause = value++; - for (size_t index = 0; index < base::size(mips64->fpregs.dregs); ++index) { + for (size_t index = 0; index < std::size(mips64->fpregs.dregs); ++index) { mips64->fpregs.dregs[index] = static_cast(value++); } diff --git a/snapshot/win/cpu_context_win_test.cc b/snapshot/win/cpu_context_win_test.cc index 15f766777b..ab8b8b313a 100644 --- a/snapshot/win/cpu_context_win_test.cc +++ b/snapshot/win/cpu_context_win_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/cpu_context.h" @@ -87,13 +88,13 @@ void TestInitializeX86Context_FsaveWithoutFxsave() { for (size_t st_mm = 0; st_mm < 7; ++st_mm) { EXPECT_EQ( BytesToHexString(cpu_context_x86.fxsave.st_mm[st_mm].st, - base::size(cpu_context_x86.fxsave.st_mm[st_mm].st)), - std::string(base::size(cpu_context_x86.fxsave.st_mm[st_mm].st) * 2, + std::size(cpu_context_x86.fxsave.st_mm[st_mm].st)), + std::string(std::size(cpu_context_x86.fxsave.st_mm[st_mm].st) * 2, '0')) << "st_mm " << st_mm; } EXPECT_EQ(BytesToHexString(cpu_context_x86.fxsave.st_mm[7].st, - base::size(cpu_context_x86.fxsave.st_mm[7].st)), + std::size(cpu_context_x86.fxsave.st_mm[7].st)), "0000000000000080ff7f"); EXPECT_EQ(cpu_context_x86.dr0, 3u); diff --git a/snapshot/win/crashpad_snapshot_test_image_reader.cc b/snapshot/win/crashpad_snapshot_test_image_reader.cc index 94d0e47d84..65c7783183 100644 --- a/snapshot/win/crashpad_snapshot_test_image_reader.cc +++ b/snapshot/win/crashpad_snapshot_test_image_reader.cc @@ -14,7 +14,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "client/crashpad_info.h" #include "util/file/file_io.h" @@ -29,7 +30,7 @@ DWORD WINAPI LotsOfReferencesThreadProc(void* param) { // Allocate a bunch of pointers to things on the stack. int* pointers[1000]; - for (size_t i = 0; i < base::size(pointers); ++i) { + for (size_t i = 0; i < std::size(pointers); ++i) { pointers[i] = new int[2048]; } @@ -53,7 +54,7 @@ int wmain(int argc, wchar_t* argv[]) { // verify the cap on pointed-to memory. crashpad::Semaphore semaphore(0); crashpad::ScopedKernelHANDLE threads[100]; - for (size_t i = 0; i < base::size(threads); ++i) { + for (size_t i = 0; i < std::size(threads); ++i) { threads[i].reset(CreateThread(nullptr, 0, &LotsOfReferencesThreadProc, @@ -66,7 +67,7 @@ int wmain(int argc, wchar_t* argv[]) { } } - for (size_t i = 0; i < base::size(threads); ++i) { + for (size_t i = 0; i < std::size(threads); ++i) { semaphore.Wait(); } diff --git a/snapshot/win/pe_image_annotations_reader.cc b/snapshot/win/pe_image_annotations_reader.cc index 494b339804..9130e6d4ff 100644 --- a/snapshot/win/pe_image_annotations_reader.cc +++ b/snapshot/win/pe_image_annotations_reader.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "client/annotation.h" @@ -157,8 +158,7 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( snapshot.type = current.type; char name[Annotation::kNameMaxLength]; - if (!process_reader_->Memory()->Read( - current.name, base::size(name), name)) { + if (!process_reader_->Memory()->Read(current.name, std::size(name), name)) { LOG(WARNING) << "could not read annotation name at index " << index << " in " << base::WideToUTF8(name_); continue; diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc index bc4511b376..2a7b151099 100644 --- a/snapshot/win/pe_image_reader.cc +++ b/snapshot/win/pe_image_reader.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" @@ -288,7 +288,7 @@ bool PEImageReader::VSFixedFileInfo( version_info.wType != 0 || wcsncmp(version_info.szKey, L"VS_VERSION_INFO", - base::size(version_info.szKey)) != 0) { + std::size(version_info.szKey)) != 0) { LOG(WARNING) << "unexpected VS_VERSIONINFO in " << module_subrange_reader_.name(); return false; diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 68933bbe63..709e56b21a 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" #include "test/win/win_multiprocess.h" #include "util/misc/from_pointer_cast.h" @@ -44,7 +45,7 @@ TEST(ProcessReaderWin, SelfBasic) { EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[base::size(kTestMemory)]; + char buffer[std::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); @@ -193,7 +194,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { // the pipe. CheckedReadFileAtEOF(ReadPipeHandle()); - for (size_t i = 0; i < base::size(threads); ++i) + for (size_t i = 0; i < std::size(threads); ++i) done.Signal(); for (auto& thread : threads) thread.Join(); diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index fee843c76d..f1a20b5d7d 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -332,7 +332,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { uet.TimeDateStamp, base::WideToUTF8(base::WStringPiece( uet.ImageName, - wcsnlen(uet.ImageName, base::size(uet.ImageName)))))); + wcsnlen(uet.ImageName, std::size(uet.ImageName)))))); } } } @@ -532,9 +532,9 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( env_block.resize( static_cast(bytes_read / sizeof(env_block[0]))); static constexpr wchar_t terminator[] = {0, 0}; - size_t at = env_block.find(std::wstring(terminator, base::size(terminator))); + size_t at = env_block.find(std::wstring(terminator, std::size(terminator))); if (at != std::wstring::npos) - env_block.resize(at + base::size(terminator)); + env_block.resize(at + std::size(terminator)); return env_block.size() * sizeof(env_block[0]); } diff --git a/test/hex_string.h b/test/hex_string.h index b0d445319e..be0143b7b3 100644 --- a/test/hex_string.h +++ b/test/hex_string.h @@ -29,8 +29,8 @@ namespace test { //! uint8_t expected[10]; //! uint8_t observed[10]; //! // … -//! EXPECT_EQ(BytesToHexString(observed, base::size(observed)), -//! BytesToHexString(expected, base::size(expected))); +//! EXPECT_EQ(BytesToHexString(observed, std::size(observed)), +//! BytesToHexString(expected, std::size(expected))); //! \endcode std::string BytesToHexString(const void* bytes, size_t length); diff --git a/test/hex_string_test.cc b/test/hex_string_test.cc index ac6343bf58..13aa311a31 100644 --- a/test/hex_string_test.cc +++ b/test/hex_string_test.cc @@ -14,7 +14,8 @@ #include "test/hex_string.h" -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" namespace crashpad { @@ -25,7 +26,7 @@ TEST(HexString, HexString) { EXPECT_EQ(BytesToHexString(nullptr, 0), ""); static constexpr char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_"; - EXPECT_EQ(BytesToHexString(kBytes, base::size(kBytes)), + EXPECT_EQ(BytesToHexString(kBytes, std::size(kBytes)), "41626331323378797a200a7ff09f92a95f00"); } diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index bbe6f7dd95..d55937772e 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -21,13 +21,13 @@ #include #include +#include #include #include #include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/files/file_path.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -111,14 +111,14 @@ bool StringToBool(const char* string, bool* boolean) { "set", }; - for (size_t index = 0; index < base::size(kFalseWords); ++index) { + for (size_t index = 0; index < std::size(kFalseWords); ++index) { if (strcasecmp(string, kFalseWords[index]) == 0) { *boolean = false; return true; } } - for (size_t index = 0; index < base::size(kTrueWords); ++index) { + for (size_t index = 0; index < std::size(kTrueWords); ++index) { if (strcasecmp(string, kTrueWords[index]) == 0) { *boolean = true; return true; @@ -161,7 +161,7 @@ bool StringToTime(const char* string, time_t* out_time, bool utc) { "%+", }; - for (size_t index = 0; index < base::size(kFormats); ++index) { + for (size_t index = 0; index < std::size(kFormats); ++index) { tm time_tm; const char* strptime_result = strptime(string, kFormats[index], &time_tm); if (strptime_result == end) { @@ -216,7 +216,7 @@ std::string TimeToString(time_t out_time, bool utc) { char string[64]; CHECK_NE( - strftime(string, base::size(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm), + strftime(string, std::size(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm), 0u); return std::string(string); diff --git a/util/file/delimited_file_reader.cc b/util/file/delimited_file_reader.cc index f899dbf340..015a09dc50 100644 --- a/util/file/delimited_file_reader.cc +++ b/util/file/delimited_file_reader.cc @@ -17,10 +17,10 @@ #include #include +#include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/numerics/safe_conversions.h" namespace crashpad { @@ -76,7 +76,7 @@ DelimitedFileReader::Result DelimitedFileReader::GetDelim(char delimiter, return Result::kEndOfFile; } - DCHECK_LE(static_cast(read_result), base::size(buf_)); + DCHECK_LE(static_cast(read_result), std::size(buf_)); DCHECK( base::IsValueInRangeForNumericType(read_result)); buf_len_ = static_cast(read_result); diff --git a/util/file/delimited_file_reader_test.cc b/util/file/delimited_file_reader_test.cc index 05e610119d..5cc1f0fc7f 100644 --- a/util/file/delimited_file_reader_test.cc +++ b/util/file/delimited_file_reader_test.cc @@ -14,9 +14,9 @@ #include "util/file/delimited_file_reader.h" +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -260,7 +260,7 @@ TEST(DelimitedFileReader, ReallyLongMultiLineFile) { TEST(DelimitedFileReader, EmbeddedNUL) { static constexpr char kString[] = "embedded\0NUL\n"; StringFile string_file; - string_file.SetString(std::string(kString, base::size(kString) - 1)); + string_file.SetString(std::string(kString, std::size(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); std::string line; @@ -278,7 +278,7 @@ TEST(DelimitedFileReader, EmbeddedNUL) { TEST(DelimitedFileReader, NULDelimiter) { static constexpr char kString[] = "aa\0b\0ccc\0"; StringFile string_file; - string_file.SetString(std::string(kString, base::size(kString) - 1)); + string_file.SetString(std::string(kString, std::size(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); std::string field; @@ -302,7 +302,7 @@ TEST(DelimitedFileReader, NULDelimiter) { TEST(DelimitedFileReader, EdgeCases) { static constexpr size_t kSizes[] = {4094, 4095, 4096, 4097, 8190, 8191, 8192, 8193}; - for (size_t index = 0; index < base::size(kSizes); ++index) { + for (size_t index = 0; index < std::size(kSizes); ++index) { size_t size = kSizes[index]; SCOPED_TRACE( base::StringPrintf("index %" PRIuS ", size %" PRIuS, index, size)); diff --git a/util/file/file_io_test.cc b/util/file/file_io_test.cc index f970e3564b..2d45cfb6c5 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -16,11 +16,11 @@ #include +#include #include #include #include "base/atomicops.h" -#include "base/cxx17_backports.h" #include "base/files/file_path.h" #include "build/build_config.h" #include "gmock/gmock.h" @@ -643,7 +643,7 @@ void LockingTest(FileLocking main_lock, FileLocking other_locks) { LockingTestThread threads[20]; int expected_iterations = 0; - for (size_t index = 0; index < base::size(threads); ++index) { + for (size_t index = 0; index < std::size(threads); ++index) { int iterations_for_this_thread = static_cast(index * 10); threads[index].Init( (other_locks == FileLocking::kShared) diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index 878103d9dc..04d47f5e41 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/files/file_path.h" #include "base/logging.h" #include "util/file/file_io.h" @@ -48,7 +49,7 @@ bool ProcStatReader::Initialize(PtraceConnection* connection, pid_t tid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); char path[32]; - snprintf(path, base::size(path), "/proc/%d/stat", tid); + snprintf(path, std::size(path), "/proc/%d/stat", tid); if (!connection->ReadFileContents(base::FilePath(path), &contents_)) { return false; } diff --git a/util/linux/proc_task_reader.cc b/util/linux/proc_task_reader.cc index ca62db2712..0d2fb90b1b 100644 --- a/util/linux/proc_task_reader.cc +++ b/util/linux/proc_task_reader.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/files/file_path.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" @@ -29,7 +30,7 @@ bool ReadThreadIDs(pid_t pid, std::vector* tids) { DCHECK(tids->empty()); char path[32]; - snprintf(path, base::size(path), "/proc/%d/task", pid); + snprintf(path, std::size(path), "/proc/%d/task", pid); DirectoryReader reader; if (!reader.Open(base::FilePath(path))) { return false; diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index 9a34722ae2..1863841f73 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "util/file/file_io.h" @@ -265,7 +265,7 @@ bool PtraceClient::Threads(std::vector* threads) { threads->push_back(pid_); char path[32]; - snprintf(path, base::size(path), "/proc/%d/task", pid_); + snprintf(path, std::size(path), "/proc/%d/task", pid_); PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeListDirectory; diff --git a/util/mac/checked_mach_address_range_test.cc b/util/mac/checked_mach_address_range_test.cc index 4ef26fd923..7f26d25596 100644 --- a/util/mac/checked_mach_address_range_test.cc +++ b/util/mac/checked_mach_address_range_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -116,7 +116,7 @@ TEST(CheckedMachAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, base 0x%llx, size 0x%llx", index, @@ -166,7 +166,7 @@ TEST(CheckedMachAddressRange, ContainsValue) { CheckedMachAddressRange parent_range_32(false, 0x2000, 0x1000); ASSERT_TRUE(parent_range_32.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, value 0x%llx", index, testcase.value)); @@ -223,7 +223,7 @@ TEST(CheckedMachAddressRange, ContainsRange) { CheckedMachAddressRange parent_range_32(false, 0x2000, 0x1000); ASSERT_TRUE(parent_range_32.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, base 0x%llx, size 0x%llx", index, diff --git a/util/mac/launchd_test.mm b/util/mac/launchd_test.mm index 2e49ee665b..21920598ff 100644 --- a/util/mac/launchd_test.mm +++ b/util/mac/launchd_test.mm @@ -20,9 +20,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/mac/scoped_launch_data.h" #include "gtest/gtest.h" #include "util/stdlib/objc.h" @@ -58,7 +58,7 @@ @0xfedcba9876543210, }; - for (size_t index = 0; index < base::size(integer_nses); ++index) { + for (size_t index = 0; index < std::size(integer_nses); ++index) { NSNumber* integer_ns = integer_nses[index]; launch_data.reset(CFPropertyToLaunchData(integer_ns)); ASSERT_TRUE(launch_data.get()); @@ -88,7 +88,7 @@ @(std::numeric_limits::signaling_NaN()), }; - for (size_t index = 0; index < base::size(double_nses); ++index) { + for (size_t index = 0; index < std::size(double_nses); ++index) { NSNumber* double_ns = double_nses[index]; launch_data.reset(CFPropertyToLaunchData(double_ns)); ASSERT_TRUE(launch_data.get()); @@ -114,7 +114,7 @@ @YES, }; - for (size_t index = 0; index < base::size(bool_nses); ++index) { + for (size_t index = 0; index < std::size(bool_nses); ++index) { NSNumber* bool_ns = bool_nses[index]; launch_data.reset(CFPropertyToLaunchData(bool_ns)); ASSERT_TRUE(launch_data.get()); @@ -138,7 +138,7 @@ @"Üñîçø∂é", }; - for (size_t index = 0; index < base::size(string_nses); ++index) { + for (size_t index = 0; index < std::size(string_nses); ++index) { NSString* string_ns = string_nses[index]; launch_data.reset(CFPropertyToLaunchData(string_ns)); ASSERT_TRUE(launch_data.get()); diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index 28fdbae6db..d0e58030ff 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -24,10 +24,10 @@ #include #include +#include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" @@ -167,8 +167,8 @@ mach_port_t ChildPortHandshakeServer::RunServer( 0, 0, nullptr); - int rv = HANDLE_EINTR(kevent( - kq.get(), changelist, base::size(changelist), nullptr, 0, nullptr)); + int rv = HANDLE_EINTR( + kevent(kq.get(), changelist, std::size(changelist), nullptr, 0, nullptr)); PCHECK(rv != -1) << "kevent"; ChildPortServer child_port_server(this); diff --git a/util/mach/child_port_server.cc b/util/mach/child_port_server.cc index 927342942f..9323723c37 100644 --- a/util/mach/child_port_server.cc +++ b/util/mach/child_port_server.cc @@ -14,7 +14,8 @@ #include "util/mach/child_port_server.h" -#include "base/cxx17_backports.h" +#include + #include "util/mach/child_portServer.h" #include "util/mach/mach_message.h" @@ -90,7 +91,7 @@ std::set ChildPortServer::MachMessageServerRequestIDs() { static constexpr mach_msg_id_t request_ids[] = {kMachMessageIDChildPortCheckIn}; return std::set(&request_ids[0], - &request_ids[base::size(request_ids)]); + &request_ids[std::size(request_ids)]); } mach_msg_size_t ChildPortServer::MachMessageServerRequestSize() { diff --git a/util/mach/composite_mach_message_server_test.cc b/util/mach/composite_mach_message_server_test.cc index 91a3851f2e..36fd6ac08e 100644 --- a/util/mach/composite_mach_message_server_test.cc +++ b/util/mach/composite_mach_message_server_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/gtest_death.h" @@ -198,7 +199,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { TestMachMessageHandler handlers[3]; std::set expect_request_ids; - for (size_t index = 0; index < base::size(kRequestIDs0); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs0); ++index) { const mach_msg_id_t request_id = kRequestIDs0[index]; handlers[0].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -207,7 +208,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[0].SetReplySize(sizeof(mig_reply_error_t)); handlers[0].SetReturnCodes(true, kReturnCode0, false); - for (size_t index = 0; index < base::size(kRequestIDs1); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs1); ++index) { const mach_msg_id_t request_id = kRequestIDs1[index]; handlers[1].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -216,7 +217,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[1].SetReplySize(200); handlers[1].SetReturnCodes(false, kReturnCode1, true); - for (size_t index = 0; index < base::size(kRequestIDs2); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs2); ++index) { const mach_msg_id_t request_id = kRequestIDs2[index]; handlers[2].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -254,7 +255,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { // Send messages with known request IDs. - for (size_t index = 0; index < base::size(kRequestIDs0); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs0); ++index) { request.header.msgh_id = kRequestIDs0[index]; SCOPED_TRACE(base::StringPrintf( "handler 0, index %zu, id %d", index, request.header.msgh_id)); @@ -265,7 +266,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_FALSE(destroy_complex_request); } - for (size_t index = 0; index < base::size(kRequestIDs1); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs1); ++index) { request.header.msgh_id = kRequestIDs1[index]; SCOPED_TRACE(base::StringPrintf( "handler 1, index %zu, id %d", index, request.header.msgh_id)); @@ -276,7 +277,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_TRUE(destroy_complex_request); } - for (size_t index = 0; index < base::size(kRequestIDs2); ++index) { + for (size_t index = 0; index < std::size(kRequestIDs2); ++index) { request.header.msgh_id = kRequestIDs2[index]; SCOPED_TRACE(base::StringPrintf( "handler 2, index %zu, id %d", index, request.header.msgh_id)); diff --git a/util/mach/exc_client_variants_test.cc b/util/mach/exc_client_variants_test.cc index aba72052fb..700eb5f8df 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -19,7 +19,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" @@ -184,11 +185,11 @@ class TestExcClientVariants : public MachMultiprocess, // These aren’t real flavors, it’s just for testing. flavor = exception_ + 10; flavor_p = &flavor; - for (size_t index = 0; index < base::size(old_state); ++index) { + for (size_t index = 0; index < std::size(old_state); ++index) { old_state[index] = index; } old_state_p = reinterpret_cast(&old_state); - old_state_count = base::size(old_state); + old_state_count = std::size(old_state); // new_state and new_state_count are out parameters that the server should // never see or use, so set them to bogus values. The call to the server @@ -205,7 +206,7 @@ class TestExcClientVariants : public MachMultiprocess, task, exception, code, - base::size(code), + std::size(code), flavor_p, old_state_p, old_state_count, @@ -274,7 +275,7 @@ TEST(ExcClientVariants, UniversalExceptionRaise) { kMachExceptionCodes | EXCEPTION_STATE_IDENTITY, }; - for (size_t index = 0; index < base::size(kBehaviors); ++index) { + for (size_t index = 0; index < std::size(kBehaviors); ++index) { exception_behavior_t behavior = kBehaviors[index]; SCOPED_TRACE(base::StringPrintf("index %zu, behavior %d", index, behavior)); diff --git a/util/mach/exc_server_variants.cc b/util/mach/exc_server_variants.cc index 9d36f3b0a2..2941cb29e9 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "build/build_config.h" #include "util/mac/mac_util.h" #include "util/mach/composite_mach_message_server.h" @@ -246,7 +246,7 @@ class ExcServer : public MachMessageServer::Interface { Traits::kMachMessageIDExceptionRaiseStateIdentity, }; return std::set(&request_ids[0], - &request_ids[base::size(request_ids)]); + &request_ids[std::size(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { @@ -321,7 +321,7 @@ bool ExcServer::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateReply; Reply* out_reply = reinterpret_cast(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = base::size(out_reply->new_state); + out_reply->new_stateCnt = std::size(out_reply->new_state); out_reply->RetCode = interface_->CatchExceptionRaiseState(in_header->msgh_local_port, in_request->exception, @@ -364,7 +364,7 @@ bool ExcServer::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateIdentityReply; Reply* out_reply = reinterpret_cast(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = base::size(out_reply->new_state); + out_reply->new_stateCnt = std::size(out_reply->new_state); out_reply->RetCode = interface_->CatchExceptionRaiseStateIdentity( in_header->msgh_local_port, in_request->thread.name, diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index f5be0ea04b..b0fcef092c 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -19,7 +19,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gmock/gmock.h" @@ -232,7 +233,7 @@ struct __attribute__((packed, aligned(4))) ExceptionRaiseStateReply { EXPECT_EQ(memcmp(&NDR, &NDR_record, sizeof(NDR)), 0); EXPECT_EQ(RetCode, KERN_SUCCESS); EXPECT_EQ(flavor, kThreadStateFlavor); - EXPECT_EQ(new_stateCnt, base::size(new_state)); + EXPECT_EQ(new_stateCnt, std::size(new_state)); } mach_msg_header_t Head; @@ -664,7 +665,7 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(base::size(reply.new_state)), + IsThreadStateAndCount(std::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -713,7 +714,7 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(base::size(reply.new_state)), + IsThreadStateAndCount(std::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -807,7 +808,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(base::size(reply.new_state)), + IsThreadStateAndCount(std::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -857,7 +858,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(base::size(reply.new_state)), + IsThreadStateAndCount(std::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -911,7 +912,7 @@ TEST(ExcServerVariants, MockUnknownID) { 2508, }; - for (size_t index = 0; index < base::size(unknown_ids); ++index) { + for (size_t index = 0; index < std::size(unknown_ids); ++index) { mach_msg_id_t id = unknown_ids[index]; SCOPED_TRACE(base::StringPrintf("unknown id %d", id)); @@ -1190,7 +1191,7 @@ TEST(ExcServerVariants, ThreadStates) { #endif }; - for (size_t index = 0; index < base::size(test_data); ++index) { + for (size_t index = 0; index < std::size(test_data); ++index) { const auto& test = test_data[index]; SCOPED_TRACE( base::StringPrintf("index %zu, flavor %d", index, test.flavor)); @@ -1270,7 +1271,7 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { KERN_SUCCESS}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, behavior %d, set_thread_state %s", @@ -1289,8 +1290,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { static constexpr natural_t old_state[] = {1, 2, 3, 4, 5}; natural_t new_state[10] = {}; - constexpr mach_msg_type_number_t old_state_count = base::size(old_state); - mach_msg_type_number_t new_state_count = base::size(new_state); + constexpr mach_msg_type_number_t old_state_count = std::size(old_state); + mach_msg_type_number_t new_state_count = std::size(new_state); // EXCEPTION_DEFAULT (with or without MACH_EXCEPTION_CODES) is not // state-carrying. new_state and new_state_count should be untouched. @@ -1299,8 +1300,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, base::size(new_state)); - for (size_t i = 0; i < base::size(new_state); ++i) { + EXPECT_EQ(new_state_count, std::size(new_state)); + for (size_t i = 0; i < std::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1309,8 +1310,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, base::size(new_state)); - for (size_t i = 0; i < base::size(new_state); ++i) { + EXPECT_EQ(new_state_count, std::size(new_state)); + for (size_t i = 0; i < std::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1322,7 +1323,7 @@ TEST(ExcServerVariants, ExcServerCopyState) { for (size_t i = 0; i < copy_limit; ++i) { EXPECT_EQ(new_state[i], old_state[i]) << "i " << i; } - for (size_t i = copy_limit; i < base::size(new_state); ++i) { + for (size_t i = copy_limit; i < std::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1338,23 +1339,23 @@ TEST(ExcServerVariants, ExcServerCopyState) { for (size_t i = 0; i < copy_limit; ++i) { EXPECT_EQ(new_state[i], old_state[i]) << "i " << i; } - for (size_t i = copy_limit; i < base::size(new_state); ++i) { + for (size_t i = copy_limit; i < std::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } // This is a state-carrying exception where all of old_state is copied to // new_state, which is large enough to receive it and then some. - new_state_count = base::size(new_state); + new_state_count = std::size(new_state); ExcServerCopyState(MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY, old_state, old_state_count, new_state, &new_state_count); EXPECT_EQ(new_state_count, old_state_count); - for (size_t i = 0; i < base::size(old_state); ++i) { + for (size_t i = 0; i < std::size(old_state); ++i) { EXPECT_EQ(new_state[i], old_state[i]) << "i " << i; } - for (size_t i = base::size(old_state); i < base::size(new_state); ++i) { + for (size_t i = std::size(old_state); i < std::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } } diff --git a/util/mach/exception_behaviors_test.cc b/util/mach/exception_behaviors_test.cc index e6abd25fbc..8e3d0f4b79 100644 --- a/util/mach/exception_behaviors_test.cc +++ b/util/mach/exception_behaviors_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/mach_extensions.h" @@ -53,7 +54,7 @@ TEST(ExceptionBehaviors, ExceptionBehaviors) { EXCEPTION_STATE_IDENTITY}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, behavior %d", index, test_data.behavior)); diff --git a/util/mach/exception_types_test.cc b/util/mach/exception_types_test.cc index 3e777ef246..fb095fab0e 100644 --- a/util/mach/exception_types_test.cc +++ b/util/mach/exception_types_test.cc @@ -20,7 +20,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -71,7 +72,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { // TODO(macos_arm64): Add arm64 test data. }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, code_0 0x%llx", index, test_data.code_0)); @@ -88,7 +89,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { // Now make sure that ExcCrashRecoverOriginalException() properly ignores // optional arguments. - static_assert(base::size(kTestData) >= 1, "must have something to test"); + static_assert(std::size(kTestData) >= 1, "must have something to test"); const auto& test_data = kTestData[0]; EXPECT_EQ( ExcCrashRecoverOriginalException(test_data.code_0, nullptr, nullptr), @@ -248,7 +249,7 @@ TEST(ExceptionTypes, ExceptionCodeForMetrics) { {0x00010000, 0x00010000, static_cast(0xffffffff)}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, exception 0x%x, code_0 0x%llx", index, diff --git a/util/mach/mach_message_server_test.cc b/util/mach/mach_message_server_test.cc index 6785827b98..51a0b4cab9 100644 --- a/util/mach/mach_message_server_test.cc +++ b/util/mach/mach_message_server_test.cc @@ -19,9 +19,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/mac/scoped_mach_port.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" @@ -284,7 +284,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, std::set MachMessageServerRequestIDs() override { static constexpr mach_msg_id_t request_ids[] = {kRequestMessageID}; return std::set(&request_ids[0], - &request_ids[base::size(request_ids)]); + &request_ids[std::size(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { diff --git a/util/mach/notify_server.cc b/util/mach/notify_server.cc index e625419e93..b16c6fb3e7 100644 --- a/util/mach/notify_server.cc +++ b/util/mach/notify_server.cc @@ -14,7 +14,8 @@ #include "util/mach/notify_server.h" -#include "base/cxx17_backports.h" +#include + #include "util/mach/mach_message.h" #include "util/mach/notifyServer.h" @@ -227,7 +228,7 @@ std::set NotifyServer::MachMessageServerRequestIDs() { MACH_NOTIFY_DEAD_NAME, }; return std::set(&request_ids[0], - &request_ids[base::size(request_ids)]); + &request_ids[std::size(request_ids)]); } mach_msg_size_t NotifyServer::MachMessageServerRequestSize() { diff --git a/util/mach/symbolic_constants_mach.cc b/util/mach/symbolic_constants_mach.cc index 47090086e4..457a0ca2b7 100644 --- a/util/mach/symbolic_constants_mach.cc +++ b/util/mach/symbolic_constants_mach.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" @@ -45,7 +46,7 @@ constexpr const char* kExceptionNames[] = { "GUARD", "CORPSE_NOTIFY", }; -static_assert(base::size(kExceptionNames) == EXC_TYPES_COUNT, +static_assert(std::size(kExceptionNames) == EXC_TYPES_COUNT, "kExceptionNames length"); constexpr char kExcPrefix[] = "EXC_"; @@ -170,7 +171,7 @@ std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { {"_STATE32", "32"}, {"_STATE64", "64"}, }; - for (size_t suffix_index = 0; suffix_index < base::size(kStateSuffixes); + for (size_t suffix_index = 0; suffix_index < std::size(kStateSuffixes); ++suffix_index) { const char* suffix = kStateSuffixes[suffix_index].orig; size_t suffix_len = strlen(suffix); @@ -194,7 +195,7 @@ namespace crashpad { std::string ExceptionToString(exception_type_t exception, SymbolicConstantToStringOptions options) { const char* exception_name = - implicit_cast(exception) < base::size(kExceptionNames) + implicit_cast(exception) < std::size(kExceptionNames) ? kExceptionNames[exception] : nullptr; if (!exception_name) { @@ -220,7 +221,7 @@ bool StringToException(const base::StringPiece& string, base::StringPiece short_string = can_match_full ? string.substr(strlen(kExcPrefix)) : string; for (exception_type_t index = 0; - index < implicit_cast(base::size(kExceptionNames)); + index < implicit_cast(std::size(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -250,7 +251,7 @@ std::string ExceptionMaskToString(exception_mask_t exception_mask, exception_mask_t local_exception_mask = exception_mask; std::string mask_string; bool has_forbidden_or = false; - for (size_t exception = 0; exception < base::size(kExceptionNames); + for (size_t exception = 0; exception < std::size(kExceptionNames); ++exception) { const char* exception_name = kExceptionNames[exception]; exception_mask_t exception_mask_value = 1 << exception; @@ -324,7 +325,7 @@ bool StringToExceptionMask(const base::StringPiece& string, base::StringPiece short_string = can_match_full ? string.substr(strlen(kExcMaskPrefix)) : string; for (exception_type_t index = 0; - index < implicit_cast(base::size(kExceptionNames)); + index < implicit_cast(std::size(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -363,7 +364,7 @@ std::string ExceptionBehaviorToString(exception_behavior_t behavior, const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior); const char* behavior_name = - implicit_cast(basic_behavior) < base::size(kBehaviorNames) + implicit_cast(basic_behavior) < std::size(kBehaviorNames) ? kBehaviorNames[basic_behavior] : nullptr; if (!behavior_name) { @@ -430,8 +431,7 @@ bool StringToExceptionBehavior(const base::StringPiece& string, base::StringPiece short_string = can_match_full ? sp.substr(strlen(kBehaviorPrefix)) : sp; for (exception_behavior_t index = 0; - index < - implicit_cast(base::size(kBehaviorNames)); + index < implicit_cast(std::size(kBehaviorNames)); ++index) { const char* behavior_name = kBehaviorNames[index]; if (!behavior_name) { @@ -467,13 +467,13 @@ bool StringToExceptionBehavior(const base::StringPiece& string, std::string ThreadStateFlavorToString(thread_state_flavor_t flavor, SymbolicConstantToStringOptions options) { const char* flavor_name = - implicit_cast(flavor) < base::size(kFlavorNames) + implicit_cast(flavor) < std::size(kFlavorNames) ? kFlavorNames[flavor] : nullptr; if (!flavor_name) { for (size_t generic_flavor_index = 0; - generic_flavor_index < base::size(kGenericFlavorNames); + generic_flavor_index < std::size(kGenericFlavorNames); ++generic_flavor_index) { if (flavor == kGenericFlavorNames[generic_flavor_index].flavor) { flavor_name = kGenericFlavorNames[generic_flavor_index].name; @@ -500,7 +500,7 @@ bool StringToThreadStateFlavor(const base::StringPiece& string, thread_state_flavor_t* flavor) { if ((options & kAllowFullName) || (options & kAllowShortName)) { for (thread_state_flavor_t index = 0; - index < implicit_cast(base::size(kFlavorNames)); + index < implicit_cast(std::size(kFlavorNames)); ++index) { const char* flavor_name = kFlavorNames[index]; if (!flavor_name) { @@ -520,7 +520,7 @@ bool StringToThreadStateFlavor(const base::StringPiece& string, } for (size_t generic_flavor_index = 0; - generic_flavor_index < base::size(kGenericFlavorNames); + generic_flavor_index < std::size(kGenericFlavorNames); ++generic_flavor_index) { const char* flavor_name = kGenericFlavorNames[generic_flavor_index].name; thread_state_flavor_t flavor_number = diff --git a/util/mach/symbolic_constants_mach_test.cc b/util/mach/symbolic_constants_mach_test.cc index 20c60a0ead..614a45b580 100644 --- a/util/mach/symbolic_constants_mach_test.cc +++ b/util/mach/symbolic_constants_mach_test.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -26,7 +27,7 @@ #include "util/misc/implicit_cast.h" #define NUL_TEST_DATA(string) \ - { string, base::size(string) - 1 } + { string, std::size(string) - 1 } namespace crashpad { namespace test { @@ -160,7 +161,7 @@ void TestExceptionToString(exception_type_t value, } TEST(SymbolicConstantsMach, ExceptionToString) { - for (size_t index = 0; index < base::size(kExceptionTestData); ++index) { + for (size_t index = 0; index < std::size(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionToString(kExceptionTestData[index].exception, kExceptionTestData[index].full_name, @@ -188,11 +189,11 @@ void TestStringToException(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToException) { - for (size_t option_index = 0; option_index < base::size(kNormalOptions); + for (size_t option_index = 0; option_index < std::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < base::size(kExceptionTestData); ++index) { + for (size_t index = 0; index < std::size(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_type_t exception = kExceptionTestData[index].exception; { @@ -230,7 +231,7 @@ TEST(SymbolicConstantsMach, StringToException) { "", }; - for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { + for (size_t index = 0; index < std::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToException(kNegativeTestData[index], options, false, 0); } @@ -251,7 +252,7 @@ TEST(SymbolicConstantsMach, StringToException) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < base::size(kNULTestData); ++index) { + for (size_t index = 0; index < std::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -334,7 +335,7 @@ void TestExceptionMaskToString(exception_mask_t value, } TEST(SymbolicConstantsMach, ExceptionMaskToString) { - for (size_t index = 0; index < base::size(kExceptionMaskTestData); ++index) { + for (size_t index = 0; index < std::size(kExceptionMaskTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionMaskToString(kExceptionMaskTestData[index].exception_mask, kExceptionMaskTestData[index].full_name, @@ -389,12 +390,11 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { kAllowFullName | kAllowShortName | kAllowNumber | kAllowOr, }; - for (size_t option_index = 0; option_index < base::size(kOptions); + for (size_t option_index = 0; option_index < std::size(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < base::size(kExceptionMaskTestData); - ++index) { + for (size_t index = 0; index < std::size(kExceptionMaskTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_mask_t exception_mask = kExceptionMaskTestData[index].exception_mask; @@ -445,7 +445,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { "", }; - for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { + for (size_t index = 0; index < std::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNegativeTestData[index], options, false, 0); } @@ -471,7 +471,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { NUL_TEST_DATA("ARITHMETIC|\0EMULATION"), }; - for (size_t index = 0; index < base::size(kNULTestData); ++index) { + for (size_t index = 0; index < std::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -506,7 +506,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { EXC_MASK_SYSCALL | 0x100}, }; - for (size_t index = 0; index < base::size(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < std::size(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -577,7 +577,7 @@ void TestExceptionBehaviorToString(exception_behavior_t value, } TEST(SymbolicConstantsMach, ExceptionBehaviorToString) { - for (size_t index = 0; index < base::size(kExceptionBehaviorTestData); + for (size_t index = 0; index < std::size(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionBehaviorToString(kExceptionBehaviorTestData[index].behavior, @@ -607,11 +607,11 @@ void TestStringToExceptionBehavior(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToExceptionBehavior) { - for (size_t option_index = 0; option_index < base::size(kNormalOptions); + for (size_t option_index = 0; option_index < std::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < base::size(kExceptionBehaviorTestData); + for (size_t index = 0; index < std::size(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_behavior_t behavior = @@ -657,7 +657,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { "", }; - for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { + for (size_t index = 0; index < std::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior( kNegativeTestData[index], options, false, 0); @@ -683,7 +683,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { NUL_TEST_DATA("STATE_IDENTITY|\0MACH"), }; - for (size_t index = 0; index < base::size(kNULTestData); ++index) { + for (size_t index = 0; index < std::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -720,7 +720,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { implicit_cast(MACH_EXCEPTION_CODES | 0x2)}, }; - for (size_t index = 0; index < base::size(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < std::size(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -837,7 +837,7 @@ void TestThreadStateFlavorToString(exception_type_t value, } TEST(SymbolicConstantsMach, ThreadStateFlavorToString) { - for (size_t index = 0; index < base::size(kThreadStateFlavorTestData); + for (size_t index = 0; index < std::size(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestThreadStateFlavorToString(kThreadStateFlavorTestData[index].flavor, @@ -879,11 +879,11 @@ void TestStringToThreadStateFlavor(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { - for (size_t option_index = 0; option_index < base::size(kNormalOptions); + for (size_t option_index = 0; option_index < std::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < base::size(kThreadStateFlavorTestData); + for (size_t index = 0; index < std::size(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); thread_state_flavor_t flavor = kThreadStateFlavorTestData[index].flavor; @@ -953,7 +953,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { + for (size_t index = 0; index < std::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToThreadStateFlavor( kNegativeTestData[index], options, false, 0); @@ -1019,7 +1019,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < base::size(kNULTestData); ++index) { + for (size_t index = 0; index < std::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); diff --git a/util/misc/arraysize.h b/util/misc/arraysize.h index 93a63882e4..63f49768c0 100644 --- a/util/misc/arraysize.h +++ b/util/misc/arraysize.h @@ -35,9 +35,9 @@ constexpr size_t ArraySizeHelper() noexcept { //! \brief A way of computing an array’s size. //! -//! Use this only where `base::size()` or `std::size()` won’t work, such as in -//! constant expressions (including `static_assert` expressions) that consider -//! the sizes of non-static data members. +//! Use this only where `std::size()` won’t work, such as in constant +//! expressions (including `static_assert` expressions) that consider the +//! sizes of non-static data members. #define ArraySize(array) crashpad::internal::ArraySizeHelper() #endif // CRASHPAD_UTIL_MISC_ARRAYSIZE_H_ diff --git a/util/misc/capture_context_test_util_win.cc b/util/misc/capture_context_test_util_win.cc index d1221956d8..dd9d9a6834 100644 --- a/util/misc/capture_context_test_util_win.cc +++ b/util/misc/capture_context_test_util_win.cc @@ -13,10 +13,11 @@ // limitations under the License. #include "util/misc/capture_context_test_util.h" -#include "util/win/context_wrappers.h" -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" +#include "util/win/context_wrappers.h" namespace crashpad { namespace test { @@ -59,7 +60,7 @@ void SanityCheckContext(const NativeCPUContext& context) { #if defined(ARCH_CPU_X86) // fxsave doesn’t write these bytes. - for (size_t i = 464; i < base::size(context.ExtendedRegisters); ++i) { + for (size_t i = 464; i < std::size(context.ExtendedRegisters); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.ExtendedRegisters[i], 0); } @@ -69,7 +70,7 @@ void SanityCheckContext(const NativeCPUContext& context) { EXPECT_EQ(context.FltSave.MxCsr, context.MxCsr); // fxsave doesn’t write these bytes. - for (size_t i = 0; i < base::size(context.FltSave.Reserved4); ++i) { + for (size_t i = 0; i < std::size(context.FltSave.Reserved4); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.FltSave.Reserved4[i], 0); } @@ -81,7 +82,7 @@ void SanityCheckContext(const NativeCPUContext& context) { EXPECT_EQ(context.P4Home, 0u); EXPECT_EQ(context.P5Home, 0u); EXPECT_EQ(context.P6Home, 0u); - for (size_t i = 0; i < base::size(context.VectorRegister); ++i) { + for (size_t i = 0; i < std::size(context.VectorRegister); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.VectorRegister[i].Low, 0u); EXPECT_EQ(context.VectorRegister[i].High, 0u); diff --git a/util/misc/clock_test.cc b/util/misc/clock_test.cc index a1b1a4fa4e..8c43d02b5e 100644 --- a/util/misc/clock_test.cc +++ b/util/misc/clock_test.cc @@ -17,8 +17,8 @@ #include #include +#include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" @@ -83,7 +83,7 @@ TEST(Clock, SleepNanoseconds) { static_cast(5E7), // 50 milliseconds }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const uint64_t nanoseconds = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, nanoseconds %" PRIu64, index, nanoseconds)); diff --git a/util/misc/paths_win.cc b/util/misc/paths_win.cc index 8510ccf932..9261718c00 100644 --- a/util/misc/paths_win.cc +++ b/util/misc/paths_win.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" namespace crashpad { @@ -24,14 +25,12 @@ namespace crashpad { // static bool Paths::Executable(base::FilePath* path) { wchar_t executable_path[_MAX_PATH]; - unsigned int len = - GetModuleFileName(nullptr, - executable_path, - static_cast(base::size(executable_path))); + unsigned int len = GetModuleFileName( + nullptr, executable_path, static_cast(std::size(executable_path))); if (len == 0) { PLOG(ERROR) << "GetModuleFileName"; return false; - } else if (len >= base::size(executable_path)) { + } else if (len >= std::size(executable_path)) { LOG(ERROR) << "GetModuleFileName"; return false; } diff --git a/util/misc/random_string_test.cc b/util/misc/random_string_test.cc index fac830f358..15b3a4140e 100644 --- a/util/misc/random_string_test.cc +++ b/util/misc/random_string_test.cc @@ -16,9 +16,9 @@ #include +#include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" namespace crashpad { @@ -33,7 +33,7 @@ TEST(RandomString, RandomString) { const std::string allowed_characters("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); size_t character_counts[26] = {}; - ASSERT_EQ(allowed_characters.size(), base::size(character_counts)); + ASSERT_EQ(allowed_characters.size(), std::size(character_counts)); std::set strings; @@ -61,7 +61,7 @@ TEST(RandomString, RandomString) { // Make sure every character appears at least once. It is possible, but // extremely unlikely, for a character to not appear at all. for (size_t character_index = 0; - character_index < base::size(character_counts); + character_index < std::size(character_counts); ++character_index) { EXPECT_GT(character_counts[character_index], 0u) << allowed_characters[character_index]; diff --git a/util/misc/uuid_test.cc b/util/misc/uuid_test.cc index aea126ab56..6c036633d7 100644 --- a/util/misc/uuid_test.cc +++ b/util/misc/uuid_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/scoped_generic.h" #include "base/strings/stringprintf.h" @@ -110,13 +110,13 @@ TEST(UUID, UUID) { EXPECT_NE(uuid, uuid_2); EXPECT_LT(uuid_2, uuid); --uuid.data_3; - for (size_t index = 0; index < base::size(uuid.data_4); ++index) { + for (size_t index = 0; index < std::size(uuid.data_4); ++index) { ++uuid.data_4[index]; EXPECT_NE(uuid, uuid_2); EXPECT_LT(uuid_2, uuid); --uuid.data_4[index]; } - for (size_t index = 0; index < base::size(uuid.data_5); ++index) { + for (size_t index = 0; index < std::size(uuid.data_5); ++index) { ++uuid.data_5[index]; EXPECT_NE(uuid, uuid_2); EXPECT_LT(uuid_2, uuid); @@ -207,7 +207,7 @@ TEST(UUID, FromString) { uuid_zero.InitializeToZero(); const std::string empty_uuid = uuid_zero.ToString(); - for (size_t index = 0; index < base::size(kCases); ++index) { + for (size_t index = 0; index < std::size(kCases); ++index) { const TestCase& test_case = kCases[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ": %s", index, test_case.uuid_string)); diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index 286c2ab082..e27afa22e9 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "util/net/http_transport.h" - #include #include #include #include #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/posix/eintr_wrapper.h" @@ -30,6 +29,7 @@ #include "build/build_config.h" #include "util/file/file_io.h" #include "util/net/http_body.h" +#include "util/net/http_transport.h" #include "util/net/url.h" #include "util/stdlib/string_number_conversion.h" #include "util/string/split_string.h" @@ -371,7 +371,7 @@ bool WriteRequest(Stream* stream, FileOperationResult data_bytes; do { - constexpr size_t kCRLFSize = base::size(kCRLFTerminator) - 1; + constexpr size_t kCRLFSize = std::size(kCRLFTerminator) - 1; struct __attribute__((packed)) { char size[8]; char crlf[2]; diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index cb04c2e930..117b82696c 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -22,7 +22,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/scoped_generic.h" @@ -96,7 +97,7 @@ std::string WinHttpMessage(const char* extra) { error_code, 0, msgbuf, - static_cast(base::size(msgbuf)), + static_cast(std::size(msgbuf)), nullptr); if (!len) { return base::StringPrintf("%s: error 0x%lx while retrieving error 0x%lx", diff --git a/util/numeric/checked_address_range_test.cc b/util/numeric/checked_address_range_test.cc index aa700e0a0d..1a4d93f7a6 100644 --- a/util/numeric/checked_address_range_test.cc +++ b/util/numeric/checked_address_range_test.cc @@ -16,9 +16,9 @@ #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" @@ -119,7 +119,7 @@ TEST(CheckedAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%" PRIx64 ", size 0x%" PRIx64, @@ -170,7 +170,7 @@ TEST(CheckedAddressRange, ContainsValue) { CheckedAddressRange parent_range_32(false, 0x2000, 0x1000); ASSERT_TRUE(parent_range_32.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", value 0x%" PRIx64, index, testcase.value)); @@ -227,7 +227,7 @@ TEST(CheckedAddressRange, ContainsRange) { CheckedAddressRange parent_range_32(false, 0x2000, 0x1000); ASSERT_TRUE(parent_range_32.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%" PRIx64 ", size 0x%" PRIx64, diff --git a/util/numeric/checked_range_test.cc b/util/numeric/checked_range_test.cc index ad734ba342..b4e0426163 100644 --- a/util/numeric/checked_range_test.cc +++ b/util/numeric/checked_range_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -78,7 +78,7 @@ TEST(CheckedRange, IsValid) { {0xffffffff, 0xffffffff, false}, }; - for (size_t index = 0; index < base::size(kUnsignedTestData); ++index) { + for (size_t index = 0; index < std::size(kUnsignedTestData); ++index) { const auto& testcase = kUnsignedTestData[index]; SCOPED_TRACE(base::StringPrintf("unsigned index %" PRIuS ", base 0x%x, size 0x%x", @@ -140,7 +140,7 @@ TEST(CheckedRange, IsValid) { {-1, 0xffffffff, false}, }; - for (size_t index = 0; index < base::size(kSignedTestData); ++index) { + for (size_t index = 0; index < std::size(kSignedTestData); ++index) { const auto& testcase = kSignedTestData[index]; SCOPED_TRACE(base::StringPrintf("signed index %" PRIuS ", base 0x%x, size 0x%x", @@ -186,7 +186,7 @@ TEST(CheckedRange, ContainsValue) { CheckedRange parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", value 0x%x", index, testcase.value)); @@ -234,7 +234,7 @@ TEST(CheckedRange, ContainsRange) { CheckedRange parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%x, size 0x%x", index, @@ -287,7 +287,7 @@ TEST(CheckedRange, OverlapsRange) { CheckedRange first_range(0x2000, 0x1000); ASSERT_TRUE(first_range.IsValid()); - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%x, size 0x%x", index, diff --git a/util/posix/close_multiple.cc b/util/posix/close_multiple.cc index ec15e06fff..4bafd474b8 100644 --- a/util/posix/close_multiple.cc +++ b/util/posix/close_multiple.cc @@ -21,8 +21,8 @@ #include #include +#include -#include "base/cxx17_backports.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" @@ -155,7 +155,7 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { int maxfilesperproc; size_t maxfilesperproc_size = sizeof(maxfilesperproc); if (sysctl(oid, - base::size(oid), + std::size(oid), &maxfilesperproc, &maxfilesperproc_size, nullptr, diff --git a/util/posix/process_info_mac.cc b/util/posix/process_info_mac.cc index 47d0ff4ae1..de056dd5ae 100644 --- a/util/posix/process_info_mac.cc +++ b/util/posix/process_info_mac.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "base/mac/mach_logging.h" @@ -33,7 +34,7 @@ bool ProcessInfo::InitializeWithPid(pid_t pid) { int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; size_t len = sizeof(kern_proc_info_); - if (sysctl(mib, base::size(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { + if (sysctl(mib, std::size(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { PLOG(ERROR) << "sysctl for pid " << pid; return false; } @@ -112,7 +113,7 @@ std::set ProcessInfo::SupplementaryGroups() const { const short ngroups = kern_proc_info_.kp_eproc.e_ucred.cr_ngroups; DCHECK_GE(ngroups, 0); DCHECK_LE(static_cast(ngroups), - base::size(kern_proc_info_.kp_eproc.e_ucred.cr_groups)); + std::size(kern_proc_info_.kp_eproc.e_ucred.cr_groups)); const gid_t* groups = kern_proc_info_.kp_eproc.e_ucred.cr_groups; return std::set(&groups[0], &groups[ngroups]); @@ -169,7 +170,7 @@ bool ProcessInfo::Arguments(std::vector* argv) const { do { int mib[] = {CTL_KERN, KERN_PROCARGS2, pid}; int rv = - sysctl(mib, base::size(mib), nullptr, &args_size_estimate, nullptr, 0); + sysctl(mib, std::size(mib), nullptr, &args_size_estimate, nullptr, 0); if (rv != 0) { PLOG(ERROR) << "sysctl (size) for pid " << pid; return false; @@ -184,7 +185,7 @@ bool ProcessInfo::Arguments(std::vector* argv) const { // for the reasons described above.) args_size = args_size_estimate + 32; args.resize(args_size); - rv = sysctl(mib, base::size(mib), &args[0], &args_size, nullptr, 0); + rv = sysctl(mib, std::size(mib), &args[0], &args_size, nullptr, 0); if (rv != 0) { PLOG(ERROR) << "sysctl (data) for pid " << pid; return false; diff --git a/util/posix/scoped_mmap_test.cc b/util/posix/scoped_mmap_test.cc index f8307cc698..c171b81d0a 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h" @@ -152,7 +153,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_Shrink) { EXPECT_EQ(mapping.len(), 3 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < base::size(cookies); ++index) { + for (size_t index = 0; index < std::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast( mapping.addr_as() + index * kPageSize)); } @@ -187,7 +188,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < base::size(cookies); ++index) { + for (size_t index = 0; index < std::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast( reinterpret_cast(pages) + index * kPageSize)); } @@ -198,7 +199,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.addr(), pages); EXPECT_EQ(mapping.len(), 3 * kPageSize); - for (size_t index = 0; index < base::size(cookies); ++index) { + for (size_t index = 0; index < std::size(cookies); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); EXPECT_EQ(cookies[index].Observed(), cookies[index].Expected()); } @@ -219,7 +220,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveDownAndGrow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < base::size(cookies); ++index) { + for (size_t index = 0; index < std::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast( reinterpret_cast(pages) + index * kPageSize)); } @@ -250,7 +251,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveUpAndShrink) { EXPECT_EQ(mapping.len(), 2 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < base::size(cookies); ++index) { + for (size_t index = 0; index < std::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast( reinterpret_cast(pages) + index * kPageSize)); } @@ -348,7 +349,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { EXPECT_EQ(mapping.len(), 2 * kPageSize); TestCookie two_cookies[2]; - for (size_t index = 0; index < base::size(two_cookies); ++index) { + for (size_t index = 0; index < std::size(two_cookies); ++index) { two_cookies[index].SetUp(reinterpret_cast( mapping.addr_as() + index * kPageSize)); } @@ -368,7 +369,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { EXPECT_NE(mapping.addr(), MAP_FAILED); EXPECT_EQ(mapping.len(), 2 * kPageSize); - for (size_t index = 0; index < base::size(two_cookies); ++index) { + for (size_t index = 0; index < std::size(two_cookies); ++index) { two_cookies[index].SetUp(reinterpret_cast( mapping.addr_as() + index * kPageSize)); } diff --git a/util/posix/signals.cc b/util/posix/signals.cc index 145a4332be..f53ceb2a2f 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -16,10 +16,10 @@ #include +#include #include #include "base/check_op.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "build/build_config.h" @@ -130,7 +130,7 @@ bool IsSignalInSet(int sig, const int* set, size_t set_size) { struct sigaction* Signals::OldActions::ActionForSignal(int sig) { DCHECK_GT(sig, 0); const size_t slot = sig - 1; - DCHECK_LT(slot, base::size(actions_)); + DCHECK_LT(slot, std::size(actions_)); return &actions_[slot]; } @@ -165,8 +165,7 @@ bool Signals::InstallCrashHandlers(Handler handler, OldActions* old_actions, const std::set* unhandled_signals) { return InstallHandlers( - std::vector(kCrashSignals, - kCrashSignals + base::size(kCrashSignals)), + std::vector(kCrashSignals, kCrashSignals + std::size(kCrashSignals)), handler, flags, old_actions, @@ -179,7 +178,7 @@ bool Signals::InstallTerminateHandlers(Handler handler, OldActions* old_actions) { return InstallHandlers( std::vector(kTerminateSignals, - kTerminateSignals + base::size(kTerminateSignals)), + kTerminateSignals + std::size(kTerminateSignals)), handler, flags, old_actions, @@ -324,12 +323,12 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( // static bool Signals::IsCrashSignal(int sig) { - return IsSignalInSet(sig, kCrashSignals, base::size(kCrashSignals)); + return IsSignalInSet(sig, kCrashSignals, std::size(kCrashSignals)); } // static bool Signals::IsTerminateSignal(int sig) { - return IsSignalInSet(sig, kTerminateSignals, base::size(kTerminateSignals)); + return IsSignalInSet(sig, kTerminateSignals, std::size(kTerminateSignals)); } } // namespace crashpad diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index d9b44de071..94d8e51153 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -20,9 +20,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/strings/stringprintf.h" @@ -410,7 +410,7 @@ TEST(Signals, WillSignalReraiseAutonomously) { {SIGHUP, SEGV_MAPERR, false}, {SIGINT, SI_USER, false}, }; - for (size_t index = 0; index < base::size(kTestData); ++index) { + for (size_t index = 0; index < std::size(kTestData); ++index) { const auto test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, sig %d, code %d", index, test_data.sig, test_data.code)); diff --git a/util/posix/symbolic_constants_posix.cc b/util/posix/symbolic_constants_posix.cc index 6bb08960b0..686de578c3 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "util/misc/implicit_cast.h" @@ -139,9 +140,9 @@ constexpr const char* kSignalNames[] = { }; #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) // NSIG is 64 to account for real-time signals. -static_assert(base::size(kSignalNames) == 32, "kSignalNames length"); +static_assert(std::size(kSignalNames) == 32, "kSignalNames length"); #else -static_assert(base::size(kSignalNames) == NSIG, "kSignalNames length"); +static_assert(std::size(kSignalNames) == NSIG, "kSignalNames length"); #endif constexpr char kSigPrefix[] = "SIG"; @@ -153,7 +154,7 @@ namespace crashpad { std::string SignalToString(int signal, SymbolicConstantToStringOptions options) { const char* signal_name = - implicit_cast(signal) < base::size(kSignalNames) + implicit_cast(signal) < std::size(kSignalNames) ? kSignalNames[signal] : nullptr; if (!signal_name) { @@ -178,7 +179,7 @@ bool StringToSignal(const base::StringPiece& string, string.substr(0, strlen(kSigPrefix)).compare(kSigPrefix) == 0; base::StringPiece short_string = can_match_full ? string.substr(strlen(kSigPrefix)) : string; - for (int index = 0; index < implicit_cast(base::size(kSignalNames)); + for (int index = 0; index < implicit_cast(std::size(kSignalNames)); ++index) { const char* signal_name = kSignalNames[index]; if (!signal_name) { diff --git a/util/posix/symbolic_constants_posix_test.cc b/util/posix/symbolic_constants_posix_test.cc index d59d46c16e..532f7fd2e4 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -17,14 +17,15 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" #define NUL_TEST_DATA(string) \ - { string, base::size(string) - 1 } + { string, std::size(string) - 1 } namespace crashpad { namespace test { @@ -101,7 +102,7 @@ void TestSignalToString(int value, } TEST(SymbolicConstantsPOSIX, SignalToString) { - for (size_t index = 0; index < base::size(kSignalTestData); ++index) { + for (size_t index = 0; index < std::size(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestSignalToString(kSignalTestData[index].signal, kSignalTestData[index].full_name, @@ -156,11 +157,11 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { kAllowFullName | kAllowShortName | kAllowNumber, }; - for (size_t option_index = 0; option_index < base::size(kOptions); + for (size_t option_index = 0; option_index < std::size(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < base::size(kSignalTestData); ++index) { + for (size_t index = 0; index < std::size(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); int signal = kSignalTestData[index].signal; { @@ -198,7 +199,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { "", }; - for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { + for (size_t index = 0; index < std::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToSignal(kNegativeTestData[index], options, false, 0); } @@ -219,7 +220,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < base::size(kNULTestData); ++index) { + for (size_t index = 0; index < std::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index 78ad81f2cf..381eb04338 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -14,9 +14,9 @@ #include "util/process/process_memory_range.h" +#include #include -#include "base/cxx17_backports.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/process_type.h" @@ -69,28 +69,28 @@ TEST(ProcessMemoryRange, Basic) { auto string1_addr = FromPointerCast(kTestObject.string1); auto string2_addr = FromPointerCast(kTestObject.string2); ASSERT_TRUE(range.ReadCStringSizeLimited( - string1_addr, base::size(kTestObject.string1), &string)); + string1_addr, std::size(kTestObject.string1), &string)); EXPECT_STREQ(string.c_str(), kTestObject.string1); ASSERT_TRUE(range.ReadCStringSizeLimited( - string2_addr, base::size(kTestObject.string2), &string)); + string2_addr, std::size(kTestObject.string2), &string)); EXPECT_STREQ(string.c_str(), kTestObject.string2); // Limit the range to remove access to string2. ProcessMemoryRange range2; ASSERT_TRUE(range2.Initialize(range)); ASSERT_TRUE( - range2.RestrictRange(string1_addr, base::size(kTestObject.string1))); + range2.RestrictRange(string1_addr, std::size(kTestObject.string1))); EXPECT_TRUE(range2.ReadCStringSizeLimited( - string1_addr, base::size(kTestObject.string1), &string)); + string1_addr, std::size(kTestObject.string1), &string)); EXPECT_FALSE(range2.ReadCStringSizeLimited( - string2_addr, base::size(kTestObject.string2), &string)); + string2_addr, std::size(kTestObject.string2), &string)); EXPECT_FALSE(range2.Read(object_addr, sizeof(object), &object)); // String reads fail if the NUL terminator is outside the range. ASSERT_TRUE(range2.RestrictRange(string1_addr, strlen(kTestObject.string1))); EXPECT_FALSE(range2.ReadCStringSizeLimited( - string1_addr, base::size(kTestObject.string1), &string)); + string1_addr, std::size(kTestObject.string1), &string)); // New range outside the old range. EXPECT_FALSE(range2.RestrictRange(string1_addr - 1, 1)); diff --git a/util/stdlib/string_number_conversion_test.cc b/util/stdlib/string_number_conversion_test.cc index 90b67757f4..9f4dcbeb08 100644 --- a/util/stdlib/string_number_conversion_test.cc +++ b/util/stdlib/string_number_conversion_test.cc @@ -17,10 +17,10 @@ #include #include +#include #include #include -#include "base/cxx17_backports.h" #include "gtest/gtest.h" #define STRINGIFY(a) STR(a) @@ -277,7 +277,7 @@ TEST(StringNumberConversion, StringToInt) { // "decimal digit terminates octal escape sequence". int output; std::string kEmbeddedNullInput(kEmbeddedNullInputRaw, - base::size(kEmbeddedNullInputRaw) - 1); + std::size(kEmbeddedNullInputRaw) - 1); EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output)); } @@ -307,7 +307,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { // "decimal digit terminates octal escape sequence". unsigned int output; std::string kEmbeddedNullInput(kEmbeddedNullInputRaw, - base::size(kEmbeddedNullInputRaw) - 1); + std::size(kEmbeddedNullInputRaw) - 1); EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output)); } diff --git a/util/stdlib/strlcpy_test.cc b/util/stdlib/strlcpy_test.cc index b729c24247..4cb933694d 100644 --- a/util/stdlib/strlcpy_test.cc +++ b/util/stdlib/strlcpy_test.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -53,7 +53,7 @@ TEST(strlcpy, c16lcpy) { static constexpr char16_t test_characters[] = { 0x4d, 0xe9, 0x100, 0x151, 0x1e18}; - for (size_t index = 0; index < base::size(test_characters); ++index) { + for (size_t index = 0; index < std::size(test_characters); ++index) { char16_t test_character = test_characters[index]; SCOPED_TRACE(base::StringPrintf( "character index %" PRIuS ", character 0x%x", index, test_character)); @@ -67,13 +67,13 @@ TEST(strlcpy, c16lcpy) { EXPECT_EQ(c16lcpy(destination.data, test_string.c_str(), - base::size(destination.data)), + std::size(destination.data)), length); // Make sure that the destination buffer is NUL-terminated, and that as // much of the test string was copied as could fit. size_t expected_destination_length = - std::min(length, base::size(destination.data) - 1); + std::min(length, std::size(destination.data) - 1); EXPECT_EQ(destination.data[expected_destination_length], '\0'); EXPECT_EQ(C16Len(destination.data), expected_destination_length); @@ -86,15 +86,15 @@ TEST(strlcpy, c16lcpy) { // of the buffer passed to c16lcpy. EXPECT_TRUE(C16Memcmp(expected_untouched.lead_guard, destination.lead_guard, - base::size(destination.lead_guard)) == 0); + std::size(destination.lead_guard)) == 0); size_t expected_untouched_length = - base::size(destination.data) - expected_destination_length - 1; + std::size(destination.data) - expected_destination_length - 1; EXPECT_TRUE(C16Memcmp(expected_untouched.data, &destination.data[expected_destination_length + 1], expected_untouched_length) == 0); EXPECT_TRUE(C16Memcmp(expected_untouched.trail_guard, destination.trail_guard, - base::size(destination.trail_guard)) == 0); + std::size(destination.trail_guard)) == 0); } } } diff --git a/util/stdlib/thread_safe_vector_test.cc b/util/stdlib/thread_safe_vector_test.cc index 8962430411..6558fc15ab 100644 --- a/util/stdlib/thread_safe_vector_test.cc +++ b/util/stdlib/thread_safe_vector_test.cc @@ -14,7 +14,8 @@ #include "util/stdlib/thread_safe_vector.h" -#include "base/cxx17_backports.h" +#include + #include "gtest/gtest.h" #include "util/thread/thread.h" @@ -57,12 +58,12 @@ TEST(ThreadSafeVector, ThreadSafeVector) { EXPECT_TRUE(vector.empty()); ThreadSafeVectorTestThread threads[100]; - for (size_t index = 0; index < base::size(threads); ++index) { + for (size_t index = 0; index < std::size(threads); ++index) { threads[index].SetTestParameters( &thread_safe_vector, static_cast(index * kElementsPerThread)); } - for (size_t index = 0; index < base::size(threads); ++index) { + for (size_t index = 0; index < std::size(threads); ++index) { threads[index].Start(); if (index % 10 == 0) { @@ -79,8 +80,8 @@ TEST(ThreadSafeVector, ThreadSafeVector) { std::vector drained = thread_safe_vector.Drain(); vector.insert(vector.end(), drained.begin(), drained.end()); - bool found[base::size(threads) * kElementsPerThread] = {}; - EXPECT_EQ(vector.size(), base::size(found)); + bool found[std::size(threads) * kElementsPerThread] = {}; + EXPECT_EQ(vector.size(), std::size(found)); for (int element : vector) { EXPECT_FALSE(found[element]) << element; found[element] = true; diff --git a/util/stream/base94_output_stream_test.cc b/util/stream/base94_output_stream_test.cc index d0a2985576..34c1b434cc 100644 --- a/util/stream/base94_output_stream_test.cc +++ b/util/stream/base94_output_stream_test.cc @@ -17,9 +17,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -237,7 +237,7 @@ TEST_F(Base94OutputStreamTest, WriteDeterministicLongDataMultipleTimes) { 4, 96, 40, kLongDataLength - 4 - 96 - 40}; size_t offset = 0; - for (size_t index = 0; index < base::size(kWriteLengths); ++index) { + for (size_t index = 0; index < std::size(kWriteLengths); ++index) { const size_t write_length = kWriteLengths[index]; SCOPED_TRACE(base::StringPrintf( "offset %zu, write_length %zu", offset, write_length)); diff --git a/util/stream/zlib_output_stream.cc b/util/stream/zlib_output_stream.cc index 3ae7d91296..153adbe0f7 100644 --- a/util/stream/zlib_output_stream.cc +++ b/util/stream/zlib_output_stream.cc @@ -14,8 +14,9 @@ #include "util/stream/zlib_output_stream.h" +#include + #include "base/check.h" -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "util/misc/zlib.h" @@ -65,7 +66,7 @@ bool ZlibOutputStream::Write(const uint8_t* data, size_t size) { } } zlib_stream_.next_out = buffer_; - zlib_stream_.avail_out = base::saturated_cast(base::size(buffer_)); + zlib_stream_.avail_out = base::saturated_cast(std::size(buffer_)); initialized_.set_valid(); } @@ -127,12 +128,12 @@ bool ZlibOutputStream::Flush() { } bool ZlibOutputStream::WriteOutputStream() { - auto valid_size = base::size(buffer_) - zlib_stream_.avail_out; + auto valid_size = std::size(buffer_) - zlib_stream_.avail_out; if (valid_size > 0 && !output_stream_->Write(buffer_, valid_size)) return false; zlib_stream_.next_out = buffer_; - zlib_stream_.avail_out = base::saturated_cast(base::size(buffer_)); + zlib_stream_.avail_out = base::saturated_cast(std::size(buffer_)); return true; } diff --git a/util/stream/zlib_output_stream_test.cc b/util/stream/zlib_output_stream_test.cc index 306a61b1e5..528800e386 100644 --- a/util/stream/zlib_output_stream_test.cc +++ b/util/stream/zlib_output_stream_test.cc @@ -17,8 +17,8 @@ #include #include +#include -#include "base/cxx17_backports.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -102,7 +102,7 @@ TEST_F(ZlibOutputStreamTest, WriteDeterministicLongDataMultipleTimes) { 4, 96, 40, kLongDataLength - 4 - 96 - 40}; size_t offset = 0; - for (size_t index = 0; index < base::size(kWriteLengths); ++index) { + for (size_t index = 0; index < std::size(kWriteLengths); ++index) { const size_t write_length = kWriteLengths[index]; SCOPED_TRACE(base::StringPrintf( "offset %zu, write_length %zu", offset, write_length)); diff --git a/util/synchronization/semaphore_test.cc b/util/synchronization/semaphore_test.cc index 08fc9e611a..9a6b6dec3b 100644 --- a/util/synchronization/semaphore_test.cc +++ b/util/synchronization/semaphore_test.cc @@ -16,7 +16,8 @@ #include -#include "base/cxx17_backports.h" +#include + #include "build/build_config.h" #include "gtest/gtest.h" @@ -127,7 +128,7 @@ TEST(Semaphore, TenThreaded) { Semaphore semaphore(5); ThreadMainInfo info[10]; size_t iterations = 0; - for (size_t index = 0; index < base::size(info); ++index) { + for (size_t index = 0; index < std::size(info); ++index) { info[index].semaphore = &semaphore; info[index].iterations = index; iterations += info[index].iterations; @@ -139,7 +140,7 @@ TEST(Semaphore, TenThreaded) { semaphore.Signal(); } - for (size_t index = 0; index < base::size(info); ++index) { + for (size_t index = 0; index < std::size(info); ++index) { JoinThread(&info[index]); } } diff --git a/util/thread/thread_log_messages_test.cc b/util/thread/thread_log_messages_test.cc index f3dc1a6659..efd6b53a5c 100644 --- a/util/thread/thread_log_messages_test.cc +++ b/util/thread/thread_log_messages_test.cc @@ -17,7 +17,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" @@ -65,8 +66,8 @@ TEST(ThreadLogMessages, Basic) { const std::vector& log_messages = thread_log_messages.log_messages(); - EXPECT_EQ(log_messages.size(), base::size(kMessages)); - for (size_t index = 0; index < base::size(kMessages); ++index) { + EXPECT_EQ(log_messages.size(), std::size(kMessages)); + for (size_t index = 0; index < std::size(kMessages); ++index) { ASSERT_NO_FATAL_FAILURE( ExpectLogMessage(log_messages[index], kMessages[index])) << "index " << index; @@ -149,7 +150,7 @@ TEST(ThreadLogMessages, Multithreaded) { LoggingTestThread threads[20]; int start = 0; - for (size_t index = 0; index < base::size(threads); ++index) { + for (size_t index = 0; index < std::size(threads); ++index) { threads[index].Initialize( index, static_cast(start), static_cast(index)); start += static_cast(index); diff --git a/util/win/command_line_test.cc b/util/win/command_line_test.cc index 28b9504182..6fd4b31bed 100644 --- a/util/win/command_line_test.cc +++ b/util/win/command_line_test.cc @@ -18,7 +18,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/scoped_generic.h" #include "gtest/gtest.h" #include "test/errors.h" @@ -64,7 +65,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 1", L"argument 2", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -76,7 +77,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 2", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -88,7 +89,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"she said, \"you had me at hello\"", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -101,7 +102,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument3", L"argument4", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -112,7 +113,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\\some\\directory with\\spaces\\", L"argument2", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -123,7 +124,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"", L"argument2", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } { @@ -158,7 +159,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\"\"", L" \t\n\v\"", }; - AppendCommandLineArgumentTest(base::size(kArguments), kArguments); + AppendCommandLineArgumentTest(std::size(kArguments), kArguments); } } diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc index 92d5c5d47c..6890a01cc4 100644 --- a/util/win/exception_handler_server.cc +++ b/util/win/exception_handler_server.cc @@ -18,9 +18,9 @@ #include #include +#include #include -#include "base/cxx17_backports.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" @@ -306,7 +306,7 @@ void ExceptionHandlerServer::InitializeWithInheritedDataForInitialClient( void ExceptionHandlerServer::Run(Delegate* delegate) { uint64_t shutdown_token = base::RandUint64(); ScopedKernelHANDLE thread_handles[kPipeInstances]; - for (size_t i = 0; i < base::size(thread_handles); ++i) { + for (size_t i = 0; i < std::size(thread_handles); ++i) { HANDLE pipe; if (first_pipe_instance_.is_valid()) { pipe = first_pipe_instance_.release(); @@ -358,7 +358,7 @@ void ExceptionHandlerServer::Run(Delegate* delegate) { } // Signal to the named pipe instances that they should terminate. - for (size_t i = 0; i < base::size(thread_handles); ++i) { + for (size_t i = 0; i < std::size(thread_handles); ++i) { ClientToServerMessage message; memset(&message, 0, sizeof(message)); message.type = ClientToServerMessage::kShutdown; diff --git a/util/win/ntstatus_logging.cc b/util/win/ntstatus_logging.cc index 7a1341952b..9c2630c940 100644 --- a/util/win/ntstatus_logging.cc +++ b/util/win/ntstatus_logging.cc @@ -14,9 +14,9 @@ #include "util/win/ntstatus_logging.h" +#include #include -#include "base/cxx17_backports.h" #include "base/strings/stringprintf.h" namespace { @@ -30,7 +30,7 @@ std::string FormatNtstatus(DWORD ntstatus) { ntstatus, 0, msgbuf, - static_cast(base::size(msgbuf)), + static_cast(std::size(msgbuf)), nullptr); if (len) { // Most system messages end in a period and a space. Remove the space if diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc index e3d55c6650..61dbd3d99e 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -19,7 +19,8 @@ #include #include -#include "base/cxx17_backports.h" +#include + #include "base/logging.h" #include "util/win/exception_handler_server.h" #include "util/win/loader_lock.h" @@ -209,8 +210,7 @@ const void* GetFallbackSecurityDescriptorForNamedPipeInstance(size_t* size) { ACL_REVISION, // AclRevision. 0, // Sbz1. sizeof(kSecDescBlob.sacl), // AclSize. - static_cast( - base::size(kSecDescBlob.sacl.ace)), // AceCount. + static_cast(std::size(kSecDescBlob.sacl.ace)), // AceCount. 0, // Sbz2. }, @@ -231,8 +231,8 @@ const void* GetFallbackSecurityDescriptorForNamedPipeInstance(size_t* size) { { SID_REVISION, // Revision. // SubAuthorityCount. - static_cast(base::size( - kSecDescBlob.sacl.ace[0].sid.SubAuthority)), + static_cast( + std::size(kSecDescBlob.sacl.ace[0].sid.SubAuthority)), // IdentifierAuthority. {SECURITY_MANDATORY_LABEL_AUTHORITY}, {SECURITY_MANDATORY_UNTRUSTED_RID}, // SubAuthority. diff --git a/util/win/safe_terminate_process_test.cc b/util/win/safe_terminate_process_test.cc index 6ca5aa6d3f..30a9a32da5 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -16,11 +16,11 @@ #include -#include +#include #include +#include #include "base/check.h" -#include "base/cxx17_backports.h" #include "base/files/file_path.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -150,7 +150,7 @@ TEST(SafeTerminateProcess, PatchBadly) { }; void* target = reinterpret_cast(TerminateProcess); - ScopedExecutablePatch executable_patch(target, patch, base::size(patch)); + ScopedExecutablePatch executable_patch(target, patch, std::size(patch)); // Make sure that SafeTerminateProcess() can be called. Since it’s been // patched with a no-op stub, GetLastError() shouldn’t be modified. From 13202c2ffe4b02303c721bb2f6e8efda1999aa1e Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 3 Mar 2022 10:13:48 -0800 Subject: [PATCH 124/478] linux: set ptracer in signal handlers Bug: b/215231949 Change-Id: I7e81308ed755d5f9340950fcf6a1bb70fcf66cd6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3472607 Reviewed-by: Justin Cohen Commit-Queue: Joshua Peraza --- client/crashpad_client_linux.cc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 35742be01f..53c2dadac9 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -351,17 +351,11 @@ class RequestCrashDumpHandler : public SignalHandler { } pid = creds.pid; } - if (pid > 0 && prctl(PR_SET_PTRACER, pid, 0, 0, 0) != 0) { - PLOG(WARNING) << "prctl"; - // TODO(jperaza): If this call to set the ptracer failed, it might be - // possible to try again just before a dump request, in case the - // environment has changed. Revisit ExceptionHandlerClient::SetPtracer() - // and consider saving the result of this call in ExceptionHandlerClient - // or as a member in this signal handler. ExceptionHandlerClient hasn't - // been responsible for maintaining state and a new ExceptionHandlerClient - // has been constructed as a local whenever a client needs to communicate - // with the handler. ExceptionHandlerClient lifetimes and ownership will - // need to be reconsidered if it becomes responsible for state. + if (pid > 0) { + pthread_atfork(nullptr, nullptr, SetPtracerAtFork); + if (prctl(PR_SET_PTRACER, pid, 0, 0, 0) != 0) { + PLOG(WARNING) << "prctl"; + } } sock_to_handler_.reset(sock.release()); handler_pid_ = pid; @@ -382,6 +376,13 @@ class RequestCrashDumpHandler : public SignalHandler { } void HandleCrashImpl() override { + // Attempt to set the ptracer again, in case a crash occurs after a fork, + // before SetPtracerAtFork() has been called. Ignore errors because the + // system call may be disallowed if the sandbox is engaged. + if (handler_pid_ > 0) { + sys_prctl(PR_SET_PTRACER, handler_pid_, 0, 0, 0); + } + ExceptionHandlerProtocol::ClientInformation info = {}; info.exception_information_address = FromPointerCast(&GetExceptionInfo()); @@ -404,6 +405,14 @@ class RequestCrashDumpHandler : public SignalHandler { ~RequestCrashDumpHandler() = delete; + static void SetPtracerAtFork() { + auto handler = RequestCrashDumpHandler::Get(); + if (handler->handler_pid_ > 0 && + prctl(PR_SET_PTRACER, handler->handler_pid_, 0, 0, 0) != 0) { + PLOG(WARNING) << "prctl"; + } + } + ScopedFileHandle sock_to_handler_; pid_t handler_pid_ = -1; From 3c4e37178d4b8fe3d97260dee0be7afd6bb581ad Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 8 Mar 2022 18:20:41 -0500 Subject: [PATCH 125/478] ios: Fix up concurrency in DumpWithoutCrashing and exception handling. Change signal, uncaught NSExceptions and Mach exception handlers to prevent re-entrancy with a first-exception-wins approach to prevent concurrent exceptions from trying to use the same cached intermediate dump writer. Uses compare-and-swap to either return early for reentrant signals or to wait indefinitely for anything after the first fatal exception. Change the NSException handler generated from the Objective-C exception preprocessor to not used the cached intermediate dump writer and not use the same first-exception-wins logic. This is useful because the Objective-C exception preprocessor is imperfect and may generate intermediate dumps that are not followed by process termination. Simplify DumpWithoutCrashing's ownership of its intermediate dump writer to be thread safe. Set a handler for SIGPIPE for applications that haven't already ignored or set a handler for SIGPIPE. Bug: crashpad:391 Change-Id: Ia8ae61d50be81910fa0af40325300441d9dc01b6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3401563 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/crashpad_client.h | 4 + client/crashpad_client_ios.cc | 103 ++++--- client/crashpad_client_ios_test.mm | 32 +++ client/ios_handler/in_process_handler.cc | 269 ++++++++++++------ client/ios_handler/in_process_handler.h | 153 ++++++---- .../in_process_intermediate_dump_handler.cc | 2 +- test/file.cc | 24 ++ test/file.h | 6 + test/ios/crash_type_xctest.mm | 45 +++ test/ios/host/BUILD.gn | 1 + test/ios/host/cptest_application_delegate.mm | 97 ++++++- test/ios/host/cptest_shared_object.h | 14 + 12 files changed, 569 insertions(+), 181 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 54acfba9c3..c52f216c2d 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -563,6 +563,10 @@ class CrashpadClient { //! multiple Crashpad clients can be started and stopped. Not expected to //! be used in a shipping application. static void ResetForTesting(); + + //! \brief Inject a callback into Mach handling. Intended to be used by + //! tests to trigger a reentrant exception. + static void SetMachExceptionCallbackForTesting(void (*callback)()); #endif #if BUILDFLAG(IS_APPLE) || DOXYGEN diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index ae0ddf1d48..b0e3c93e83 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -84,10 +84,31 @@ class CrashHandler : public Thread, // generate intermediate dumps for anything manually calling // raise(SIG*). In practice, this doesn’t actually happen for crash // signals that originate as hardware faults. - !Signals::InstallHandler(SIGABRT, CatchSignal, 0, &old_action_)) { + !Signals::InstallHandler( + SIGABRT, CatchAndReraiseSignal, 0, &old_action_)) { LOG(ERROR) << "Unable to initialize Crashpad."; return false; } + + // For applications that haven't ignored or set a handler for SIGPIPE: + // It’s OK for an application to set its own SIGPIPE handler (including + // SIG_IGN) before initializing Crashpad, because Crashpad will discover the + // existing handler and not install its own. + // It’s OK for Crashpad to install its own SIGPIPE handler and for the + // application to subsequently install its own (including SIG_IGN) + // afterwards, because its handler will replace Crashpad’s. + // This is useful to cover the default situation where nobody installs a + // SIGPIPE handler and the disposition is at SIG_DFL, because SIGPIPE is a + // “kill” signal (bsd/sys/signalvar.h sigprop). In that case, without + // Crashpad, SIGPIPE results in a silent and unreported kill (and not even + // ReportCrash will record it), but developers probably want to be alerted + // to the conditon. + struct sigaction sa; + if (sigaction(SIGPIPE, nullptr, &sa) == 0 && sa.sa_handler == SIG_DFL) { + Signals::InstallHandler( + SIGPIPE, CatchAndReraiseSignalDefaultAction, 0, nullptr); + } + InstallObjcExceptionPreprocessor(this); INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -104,35 +125,14 @@ class CrashHandler : public Thread, in_process_handler_.ProcessIntermediateDump(file, annotations); } - void DumpWithContext(NativeCPUContext* context) { - const mach_exception_data_type_t code[2] = {}; - static constexpr int kSimulatedException = -1; - HandleMachException(MACH_EXCEPTION_CODES, - mach_thread_self(), - kSimulatedException, - code, - std::size(code), - MACHINE_THREAD_STATE, - reinterpret_cast(context), - MACHINE_THREAD_STATE_COUNT); - } - void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); base::FilePath path; - { - // Ensure ScopedAlternateWriter's destructor is invoked before processing - // the dump, or else any crashes handled during dump processing cannot be - // written. - internal::InProcessHandler::ScopedAlternateWriter scoper( - &in_process_handler_); - if (!scoper.Open()) { - LOG(ERROR) << "Could not open writer, ignoring dump request."; - return; - } - DumpWithContext(context); - path = scoper.path(); + if (!in_process_handler_.DumpExceptionFromSimulatedMachException( + system_data_, context, &path)) { + return; } + if (process_dump) { in_process_handler_.ProcessIntermediateDump(path); } @@ -140,10 +140,8 @@ class CrashHandler : public Thread, void DumpWithoutCrashAtPath(NativeCPUContext* context, const base::FilePath& path) { - internal::InProcessHandler::ScopedAlternateWriter scoper( - &in_process_handler_); - if (scoper.OpenAtPath(path)) - DumpWithContext(context); + in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath( + system_data_, context, path); } void StartProcessingPendingReports() { @@ -151,6 +149,10 @@ class CrashHandler : public Thread, in_process_handler_.StartProcessingPendingReports(); } + void SetMachExceptionCallbackForTesting(void (*callback)()) { + in_process_handler_.SetMachExceptionCallbackForTesting(callback); + } + private: CrashHandler() = default; @@ -287,7 +289,7 @@ class CrashHandler : public Thread, void HandleUncaughtNSException(const uint64_t* frames, const size_t num_frames) override { - in_process_handler_.DumpExceptionFromNSExceptionFrames( + in_process_handler_.DumpExceptionFromNSExceptionWithFrames( system_data_, frames, num_frames); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -297,17 +299,8 @@ class CrashHandler : public Thread, void HandleUncaughtNSExceptionWithContext( NativeCPUContext* context) override { - const mach_exception_data_type_t code[2] = {0, 0}; - in_process_handler_.DumpExceptionFromMachException( - system_data_, - MACH_EXCEPTION_CODES, - mach_thread_self(), - kMachExceptionFromNSException, - code, - std::size(code), - MACHINE_THREAD_STATE, - reinterpret_cast(context), - MACHINE_THREAD_STATE_COUNT); + in_process_handler_.DumpExceptionFromNSExceptionWithContext(system_data_, + context); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -316,18 +309,30 @@ class CrashHandler : public Thread, } // The signal handler installed at OS-level. - static void CatchSignal(int signo, siginfo_t* siginfo, void* context) { + static void CatchAndReraiseSignal(int signo, + siginfo_t* siginfo, + void* context) { + Get()->HandleAndReraiseSignal(signo, + siginfo, + reinterpret_cast(context), + &(Get()->old_action_)); + } + + static void CatchAndReraiseSignalDefaultAction(int signo, + siginfo_t* siginfo, + void* context) { Get()->HandleAndReraiseSignal( - signo, siginfo, reinterpret_cast(context)); + signo, siginfo, reinterpret_cast(context), nullptr); } void HandleAndReraiseSignal(int signo, siginfo_t* siginfo, - ucontext_t* context) { + ucontext_t* context, + struct sigaction* old_action) { in_process_handler_.DumpExceptionFromSignal(system_data_, siginfo, context); // Always call system handler. - Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, &old_action_); + Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action); } base::mac::ScopedMachReceiveRight exception_port_; @@ -412,4 +417,10 @@ void CrashpadClient::ResetForTesting() { crash_handler->ResetForTesting(); } +void CrashpadClient::SetMachExceptionCallbackForTesting(void (*callback)()) { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + crash_handler->SetMachExceptionCallbackForTesting(callback); +} + } // namespace crashpad diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm index 9800d4092e..596f4b8481 100644 --- a/client/crashpad_client_ios_test.mm +++ b/client/crashpad_client_ios_test.mm @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include "test/scoped_temp_dir.h" #include "testing/platform_test.h" +#include "util/thread/thread.h" namespace crashpad { namespace test { @@ -100,6 +101,37 @@ void SetUp() override { ASSERT_EQ(reports.size(), 1u); } +class RaceThread : public Thread { + public: + explicit RaceThread() : Thread() {} + + private: + void ThreadMain() override { + for (int i = 0; i < 10; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + } +}; + +TEST_F(CrashpadIOSClient, MultipleThreadsSimulateCrash) { + RaceThread race_threads[2]; + for (RaceThread& race_thread : race_threads) { + race_thread.Start(); + } + + for (int i = 0; i < 10; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + for (RaceThread& race_thread : race_threads) { + race_thread.Join(); + } + + std::vector reports; + ASSERT_EQ(Database()->GetPendingReports(&reports), + CrashReportDatabase::kNoError); + EXPECT_EQ(reports.size(), 30u); +} + // This test is covered by a similar XCUITest, but for development purposes it's // sometimes easier and faster to run in Google Test. However, there's no way // to correctly run this in Google Test. Leave the test here, disabled, for use diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index ea86f39ebf..2ed311311e 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -17,6 +17,9 @@ #include #include +#include + +#include "base/cxx17_backports.h" #include "base/logging.h" #include "client/ios_handler/in_process_intermediate_dump_handler.h" #include "client/prune_crash_reports.h" @@ -47,6 +50,10 @@ constexpr char kLockedExtension[] = ".locked"; // uuid in the intermediate dump file name. constexpr char kBundleSeperator[] = "@"; +// Zero-ed codes used by kMachExceptionFromNSException and +// kMachExceptionSimulated. +constexpr mach_exception_data_type_t kEmulatedMachExceptionCodes[2] = {}; + } // namespace namespace crashpad { @@ -105,9 +112,16 @@ bool InProcessHandler::Initialize( system_data.IsExtension())); prune_thread_->Start(); - if (!OpenNewFile()) + base::FilePath cached_writer_path = NewLockedFilePath(); + cached_writer_ = CreateWriterWithPath(cached_writer_path); + if (!cached_writer_.get()) return false; + // Cache the locked and unlocked path here so no allocations are needed during + // any exceptions. + cached_writer_path_ = cached_writer_path.value(); + cached_writer_unlocked_path_ = + cached_writer_path.RemoveFinalExtension().value(); INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -117,16 +131,16 @@ void InProcessHandler::DumpExceptionFromSignal( siginfo_t* siginfo, ucontext_t* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { - CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer_"); + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer"); return; } - { - ScopedReport report(writer_.get(), system_data, annotations_); - InProcessIntermediateDumpHandler::WriteExceptionFromSignal( - writer_.get(), system_data, siginfo, context); - } - PostReportCleanup(); + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromSignal( + writer.GetWriter(), system_data, siginfo, context); } void InProcessHandler::DumpExceptionFromMachException( @@ -140,43 +154,123 @@ void InProcessHandler::DumpExceptionFromMachException( ConstThreadState old_state, mach_msg_type_number_t old_state_count) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { - CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer_"); + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer"); return; } - { - ScopedReport report(writer_.get(), system_data, annotations_); - InProcessIntermediateDumpHandler::WriteExceptionFromMachException( - writer_.get(), - behavior, - thread, - exception, - code, - code_count, - flavor, - old_state, - old_state_count); + + if (mach_exception_callback_for_testing_) { + mach_exception_callback_for_testing_(); + } + + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + behavior, + thread, + exception, + code, + code_count, + flavor, + old_state, + old_state_count); +} + +void InProcessHandler::DumpExceptionFromNSExceptionWithContext( + const IOSSystemDataCollector& system_data, + NativeCPUContext* context) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // This does not use the cached writer. NSExceptionWithContext comes from + // the objective-c preprocessor and uses a best-guess approach to detecting + // uncaught exceptions, and may be called multiple times. + base::FilePath writer_path = NewLockedFilePath(); + base::FilePath writer_path_unlocked = writer_path.RemoveFinalExtension(); + std::unique_ptr unsafe_writer = + CreateWriterWithPath(writer_path); + ScopedLockedWriter writer(unsafe_writer.get(), + writer_path.value().c_str(), + writer_path_unlocked.value().c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromNSException without writer"); + return; } - PostReportCleanup(); + + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + MACH_EXCEPTION_CODES, + mach_thread_self(), + kMachExceptionFromNSException, + kEmulatedMachExceptionCodes, + std::size(kEmulatedMachExceptionCodes), + MACHINE_THREAD_STATE, + reinterpret_cast(context), + MACHINE_THREAD_STATE_COUNT); } -void InProcessHandler::DumpExceptionFromNSExceptionFrames( +void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { CRASHPAD_RAW_LOG( - "Cannot DumpExceptionFromNSExceptionFrames without writer_"); + "Cannot DumpExceptionFromNSExceptionWithFrames without writer"); return; } - { - ScopedReport report( - writer_.get(), system_data, annotations_, frames, num_frames); - InProcessIntermediateDumpHandler::WriteExceptionFromNSException( - writer_.get()); + ScopedReport report( + writer.GetWriter(), system_data, annotations_, frames, num_frames); + InProcessIntermediateDumpHandler::WriteExceptionFromNSException( + writer.GetWriter()); +} + +bool InProcessHandler::DumpExceptionFromSimulatedMachException( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + base::FilePath* path) { + base::FilePath locked_path = NewLockedFilePath(); + *path = locked_path.RemoveFinalExtension(); + return DumpExceptionFromSimulatedMachExceptionAtPath( + system_data, context, locked_path); +} + +bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + const base::FilePath& path) { + // This does not use the cached writer. It's expected that simulated + // exceptions can be called multiple times and there is no expectation that + // the application is in an unsafe state, or will be terminated after this + // call. + std::unique_ptr unsafe_writer = + CreateWriterWithPath(path); + base::FilePath writer_path_unlocked = path.RemoveFinalExtension(); + ScopedLockedWriter writer(unsafe_writer.get(), + path.value().c_str(), + writer_path_unlocked.value().c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG( + "Cannot DumpExceptionFromSimulatedMachExceptionAtPath without writer"); + return false; } - PostReportCleanup(); + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + MACH_EXCEPTION_CODES, + mach_thread_self(), + kMachExceptionSimulated, + kEmulatedMachExceptionCodes, + std::size(kEmulatedMachExceptionCodes), + MACHINE_THREAD_STATE, + reinterpret_cast(context), + MACHINE_THREAD_STATE_COUNT); + return true; } void InProcessHandler::ProcessIntermediateDumps( @@ -258,6 +352,7 @@ std::vector InProcessHandler::PendingFiles() { // intermediate dumps into never getting processed. std::vector other_files; + base::FilePath cached_writer_path(cached_writer_path_); while ((result = reader.NextFile(&file)) == DirectoryReader::Result::kSuccess) { // Don't try to process files marked as 'locked' from a different bundle id. @@ -269,9 +364,9 @@ std::vector InProcessHandler::PendingFiles() { continue; } - // Never process the current file. + // Never process the current cached writer path. file = base_dir_.Append(file); - if (file == current_file_) + if (file == cached_writer_path) continue; // Otherwise, include any other unlocked, or locked files matching @@ -292,35 +387,51 @@ std::vector InProcessHandler::PendingFiles() { return files; } -InProcessHandler::ScopedAlternateWriter::ScopedAlternateWriter( - InProcessHandler* handler) - : handler_(handler) {} +IOSIntermediateDumpWriter* InProcessHandler::GetCachedWriter() { + static_assert( + std::atomic::is_always_lock_free, + "std::atomic_compare_exchange_strong uint64_t may not be signal-safe"); + uint64_t thread_self; + // This is only safe when passing pthread_self(), otherwise this can lock. + pthread_threadid_np(pthread_self(), &thread_self); + uint64_t expected = 0; + if (!std::atomic_compare_exchange_strong( + &exception_thread_id_, &expected, thread_self)) { + if (expected == thread_self) { + // Another exception came in from this thread, which means it's likely + // that our own handler crashed. We could open up a new intermediate dump + // and try to save this dump, but we could end up endlessly writing dumps. + // Instead, give up. + } else { + // Another thread is handling a crash. Sleep forever. + while (1) { + sleep(std::numeric_limits::max()); + } + } + return nullptr; + } -bool InProcessHandler::ScopedAlternateWriter::Open() { - UUID uuid; - uuid.InitializeWithNew(); - const std::string uuid_string = uuid.ToString(); - return OpenAtPath(handler_->base_dir_.Append(uuid_string)); + return cached_writer_.get(); } -bool InProcessHandler::ScopedAlternateWriter::OpenAtPath( - const base::FilePath& path) { - path_ = path; - handler_->SetOpenNewFileAfterReport(false); - original_writer_ = handler_->GetWriter(); - auto writer = std::make_unique(); - if (!writer->Open(path_)) { - DLOG(ERROR) << "Unable to open alternate intermediate dump file: " - << path_.value(); - return false; +std::unique_ptr +InProcessHandler::CreateWriterWithPath(const base::FilePath& writer_path) { + std::unique_ptr writer = + std::make_unique(); + if (!writer->Open(writer_path)) { + DLOG(ERROR) << "Unable to open intermediate dump file: " + << writer_path.value(); + return nullptr; } - handler_->SetWriter(std::move(writer)); - return true; + return writer; } -InProcessHandler::ScopedAlternateWriter::~ScopedAlternateWriter() { - handler_->SetWriter(std::move(original_writer_)); - handler_->SetOpenNewFileAfterReport(true); +const base::FilePath InProcessHandler::NewLockedFilePath() { + UUID uuid; + uuid.InitializeWithNew(); + const std::string file_string = + bundle_identifier_and_seperator_ + uuid.ToString() + kLockedExtension; + return base_dir_.Append(file_string); } InProcessHandler::ScopedReport::ScopedReport( @@ -347,34 +458,24 @@ InProcessHandler::ScopedReport::~ScopedReport() { InProcessIntermediateDumpHandler::WriteModuleInfo(writer_); } -bool InProcessHandler::OpenNewFile() { - if (!current_file_.empty()) { - // Remove .lock extension so this dump can be processed on next run by this - // client, or a client with a different bundle id that can access this dump. - base::FilePath new_path = current_file_.RemoveFinalExtension(); - MoveFileOrDirectory(current_file_, new_path); - } - UUID uuid; - uuid.InitializeWithNew(); - const std::string file_string = - bundle_identifier_and_seperator_ + uuid.ToString() + kLockedExtension; - current_file_ = base_dir_.Append(file_string); - writer_ = std::make_unique(); - if (!writer_->Open(current_file_)) { - DLOG(ERROR) << "Unable to open intermediate dump file: " - << current_file_.value(); - return false; - } - return true; -} +InProcessHandler::ScopedLockedWriter::ScopedLockedWriter( + IOSIntermediateDumpWriter* writer, + const char* writer_path, + const char* writer_unlocked_path) + : writer_path_(writer_path), + writer_unlocked_path_(writer_unlocked_path), + writer_(writer) {} + +InProcessHandler::ScopedLockedWriter::~ScopedLockedWriter() { + if (!writer_) + return; -void InProcessHandler::PostReportCleanup() { - if (writer_) { - writer_->Close(); - writer_.reset(); + writer_->Close(); + if (rename(writer_path_, writer_unlocked_path_) != 0) { + CRASHPAD_RAW_LOG("Could not remove locked extension."); + CRASHPAD_RAW_LOG(writer_path_); + CRASHPAD_RAW_LOG(writer_unlocked_path_); } - if (open_new_file_after_report_) - OpenNewFile(); } } // namespace internal diff --git a/client/ios_handler/in_process_handler.h b/client/ios_handler/in_process_handler.h index d94f19e7e6..fe638452f3 100644 --- a/client/ios_handler/in_process_handler.h +++ b/client/ios_handler/in_process_handler.h @@ -12,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include +#include #include #include #include @@ -24,6 +26,7 @@ #include "snapshot/ios/process_snapshot_ios_intermediate_dump.h" #include "util/ios/ios_intermediate_dump_writer.h" #include "util/ios/ios_system_data_collector.h" +#include "util/misc/capture_context.h" #include "util/misc/initialization_state_dcheck.h" namespace crashpad { @@ -55,6 +58,9 @@ class InProcessHandler { const IOSSystemDataCollector& system_data); //! \brief Generate an intermediate dump from a signal handler exception. + //! Writes the dump with the cached writer does not allow concurrent + //! exceptions to be written. It is expected the system will terminate + //! the application after this call. //! //! \param[in] system_data An object containing various system data points. //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal @@ -65,7 +71,10 @@ class InProcessHandler { siginfo_t* siginfo, ucontext_t* context); - //! \brief Generate an intermediate dump from a mach exception. + //! \brief Generate an intermediate dump from a mach exception. Writes the + //! dump with the cached writer does not allow concurrent exceptions to be + //! written. It is expected the system will terminate the application + //! after this call. //! //! \param[in] system_data An object containing various system data points. //! \param[in] behavior @@ -86,21 +95,62 @@ class InProcessHandler { ConstThreadState old_state, mach_msg_type_number_t old_state_count); + //! \brief Generate an intermediate dump from a NSException caught with its + //! associated CPU context. Because the method for intercepting + //! exceptions is imperfect, uses a new writer for the intermediate dump, + //! as it is possible for further exceptions to happen. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context + void DumpExceptionFromNSExceptionWithContext( + const IOSSystemDataCollector& system_data, + NativeCPUContext* context); + //! \brief Generate an intermediate dump from an uncaught NSException. //! //! When the ObjcExceptionPreprocessor does not detect an NSException as it is //! thrown, the last-chance uncaught exception handler passes a list of call //! stack frame addresses. Record them in the intermediate dump so a minidump - //! with a 'fake' call stack is generated. + //! with a 'fake' call stack is generated. Writes the dump with the cached + //! writer does not allow concurrent exceptions to be written. It is expected + //! the system will terminate the application after this call. + //! //! \param[in] system_data An object containing various system data points. //! \param[in] frames An array of call stack frame addresses. //! \param[in] num_frames The number of frames in |frames|. - void DumpExceptionFromNSExceptionFrames( + void DumpExceptionFromNSExceptionWithFrames( const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames); + //! \brief Generate a simulated intermediate dump similar to a Mach exception + //! in the same base directory as other exceptions. Does not use the + //! cached writer. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context A pointer to a NativeCPUContext object for this + //! simulated exception. + //! \param[out] path The path of the intermediate dump generated. + //! \return `true` if the pending intermediate dump could be written. + bool DumpExceptionFromSimulatedMachException( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + base::FilePath* path); + + //! \brief Generate a simulated intermediate dump similar to a Mach exception + //! at a specific path. Does not use the cached writer. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context A pointer to a NativeCPUContext object for this + //! simulated exception. + //! \param[in] path Path to where the intermediate dump should be written. + //! \return `true` if the pending intermediate dump could be written. + bool DumpExceptionFromSimulatedMachExceptionAtPath( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + const base::FilePath& path); + //! \brief Requests that the handler convert all intermediate dumps into //! minidumps and trigger an upload if possible. //! @@ -121,34 +171,11 @@ class InProcessHandler { //! pending reports. void StartProcessingPendingReports(); - //! \brief Helper that swaps out the InProcessHandler's |writer_| with an - //! alternate writer so DumpWithContext does not interfere with the - //! |writer_| created on startup. This is useful for -DumpWithoutCrash, - //! which may write to an alternate location. - class ScopedAlternateWriter { - public: - ScopedAlternateWriter(InProcessHandler* handler); - ~ScopedAlternateWriter(); - ScopedAlternateWriter(const ScopedAlternateWriter&) = delete; - ScopedAlternateWriter& operator=(const ScopedAlternateWriter&) = delete; - //! \brief Open's an alternate dump writer in the same directory as the - //! default InProcessHandler's dump writer, so the file will be - //! processed with -ProcessIntermediateDumps() - bool Open(); - - //! \brief Open's an alternate dump writer in the client provided |path|. - //! The file will only be processed by calling - //! ProcessIntermediateDump(path) - bool OpenAtPath(const base::FilePath& path); - - //! \brief The path of the alternate dump writer. - const base::FilePath& path() { return path_; } - - private: - InProcessHandler* handler_; - std::unique_ptr original_writer_; - base::FilePath path_; - }; + //! \brief Inject a callback into Mach handling. Intended to be used by + //! tests to trigger a reentrant exception. + void SetMachExceptionCallbackForTesting(void (*callback)()) { + mach_exception_callback_for_testing_ = callback; + } private: //! \brief Helper to start and end intermediate reports. @@ -170,34 +197,64 @@ class InProcessHandler { IOSIntermediateDumpWriter::ScopedRootMap rootMap_; }; - std::unique_ptr GetWriter() { - return std::move(writer_); - } + //! \brief Helper to manage closing the intermediate dump writer and unlocking + //! the dump file (renaming the file) after the report is written. + class ScopedLockedWriter { + public: + ScopedLockedWriter(IOSIntermediateDumpWriter* writer, + const char* writer_path, + const char* writer_unlocked_path); - void SetWriter(std::unique_ptr writer) { - writer_ = std::move(writer); - } + //! \brief Close the writer_ and rename to the file with path without the + //! .locked extension. + ~ScopedLockedWriter(); - void SetOpenNewFileAfterReport(bool open_new_file_after_report) { - open_new_file_after_report_ = open_new_file_after_report; - } + ScopedLockedWriter(const ScopedLockedWriter&) = delete; + ScopedLockedWriter& operator=(const ScopedLockedWriter&) = delete; + + IOSIntermediateDumpWriter* GetWriter() { return writer_; } + private: + const char* writer_path_; + const char* writer_unlocked_path_; + IOSIntermediateDumpWriter* writer_; + }; + + //! \brief Writes a minidump to the Crashpad database from the + //! \a process_snapshot, and triggers the upload_thread_ if started. void SaveSnapshot(ProcessSnapshotIOSIntermediateDump& process_snapshot); - // Process a maximum of 20 pending intermediate dumps. Dumps named with our - // bundle id get first priority to prevent spamming. + //! \brief Process a maximum of 20 pending intermediate dumps. Dumps named + //! with our bundle id get first priority to prevent spamming. std::vector PendingFiles(); - bool OpenNewFile(); - void PostReportCleanup(); + //! \brief Lock access to the cached intermediate dump writer from + //! concurrent signal, Mach exception and uncaught NSExceptions so that + //! the first exception wins. If the same thread triggers another + //! reentrant exception, ignore it. If a different thread triggers a + //! concurrent exception, sleep indefinitely. + IOSIntermediateDumpWriter* GetCachedWriter(); + + //! \brief Open a new intermediate dump writer from \a writer_path. + std::unique_ptr CreateWriterWithPath( + const base::FilePath& writer_path); + + //! \brief Generates a new file path to be used by an intermediate dump + //! writer built from base_dir_,, bundle_identifier_and_seperator_, a new + //! UUID, with a .locked extension. + const base::FilePath NewLockedFilePath(); + + // Intended to be used by tests triggering a reentrant exception. Called + // in DumpExceptionFromMachException after aquiring the cached_writer_. + void (*mach_exception_callback_for_testing_)() = nullptr; bool upload_thread_started_ = false; - bool open_new_file_after_report_ = true; std::map annotations_; base::FilePath base_dir_; - base::FilePath current_file_; - std::unique_ptr writer_; - std::unique_ptr alternate_mach_writer_; + std::string cached_writer_path_; + std::string cached_writer_unlocked_path_; + std::unique_ptr cached_writer_; + std::atomic exception_thread_id_ = 0; std::unique_ptr upload_thread_; std::unique_ptr prune_thread_; std::unique_ptr database_; diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index e4d6223ba0..88d5eb0a6e 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -647,7 +647,7 @@ void InProcessIntermediateDumpHandler::WriteProcessInfo( IntermediateDumpKey::kSystemTime, &task_thread_times.system_time); } else { - CRASHPAD_RAW_LOG("task_info task_basic_info"); + CRASHPAD_RAW_LOG("task_info thread_times_info"); } if (!annotations.empty()) { diff --git a/test/file.cc b/test/file.cc index a0ec470d70..bcfb987ec8 100644 --- a/test/file.cc +++ b/test/file.cc @@ -17,10 +17,16 @@ #include #include +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" +#if BUILDFLAG(IS_WIN) +#include +#endif + namespace crashpad { namespace test { @@ -44,6 +50,24 @@ bool FileExists(const base::FilePath& path) { return true; } +bool RemoveFileIfExists(const base::FilePath& path) { +#if BUILDFLAG(IS_POSIX) + if (unlink(path.value().c_str()) != 0 && errno != ENOENT) { + PLOG(ERROR) << "unlink " << path.value(); + return false; + } +#elif BUILDFLAG(IS_WIN) + if (!DeleteFile(path.value().c_str()) && + GetLastError() != ERROR_FILE_NOT_FOUND) { + PLOG(ERROR) << "DeleteFile " << base::WideToUTF8(path.value()); + return false; + } +#else +#error "Not implemented" +#endif + return true; +} + FileOffset FileSize(const base::FilePath& path) { #if BUILDFLAG(IS_POSIX) struct stat st; diff --git a/test/file.h b/test/file.h index 918cc3915b..451588a4df 100644 --- a/test/file.h +++ b/test/file.h @@ -30,6 +30,12 @@ namespace test { //! `false` with a Google Test failure added. bool FileExists(const base::FilePath& path); +//! \brief Removes a file if it exists, logging a message on failure. +//! +//! \param[in] path The path to the file to remove. +//! \return `true` on success. `false` on failure with a message logged. +bool RemoveFileIfExists(const base::FilePath& path); + //! \brief Determines the size of a file. //! //! \param[in] path The path of the file to check. The file must exist. diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 1022d29111..46e3bd54ae 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -299,4 +299,49 @@ - (void)testCrashWithAnnotations { isEqualToString:@"moocow"]); } +- (void)testDumpWithoutCrash { + [rootObject_ generateDumpWithoutCrash:10 threads:3]; + + // The app should not crash + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + + XCTAssertEqual([rootObject_ pendingReportCount], 30); +} + +- (void)testSimultaneousCrash { + [rootObject_ crashConcurrentSignalAndMach]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + XCTAssertEqual([rootObject_ pendingReportCount], 1); +} + +- (void)testCrashInHandlerReentrant { + app_.launchArguments = @[ @"--redirect-stderr-to-file" ]; + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + [rootObject_ crashInHandlerReentrant]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + XCTAssertEqual([rootObject_ pendingReportCount], 0); + + NSString* stderrContents = [rootObject_ stderrContents]; + NSString* errmsg = @"Cannot DumpExceptionFromSignal without writer"; + XCTAssertTrue([stderrContents containsString:errmsg]); +} + @end diff --git a/test/ios/host/BUILD.gn b/test/ios/host/BUILD.gn index 77842a98ec..1c4e37518a 100644 --- a/test/ios/host/BUILD.gn +++ b/test/ios/host/BUILD.gn @@ -43,6 +43,7 @@ static_library("app_host_sources") { "../../../build:ios_enable_arc", "../../../client", "../../../snapshot", + "../../../test", "../../../third_party/edo", ] frameworks = [ diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 212ab693e5..4cfc5e2b77 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #import "Service/Sources/EDOHostNamingService.h" #import "Service/Sources/EDOHostService.h" #import "Service/Sources/NSObject+EDOValueObject.h" +#include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "client/annotation.h" #include "client/annotation_list.h" @@ -35,9 +37,13 @@ #include "client/crashpad_client.h" #include "client/crashpad_info.h" #include "client/simple_string_dictionary.h" +#include "client/simulate_crash.h" #include "snapshot/minidump/process_snapshot_minidump.h" +#include "test/file.h" #import "test/ios/host/cptest_crash_view_controller.h" #import "test/ios/host/cptest_shared_object.h" +#include "util/file/filesystem.h" +#include "util/thread/thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -56,6 +62,14 @@ return database_dir.Append("crashpad"); } +base::FilePath GetStderrOutputFile() { + base::FilePath stderr_output([NSFileManager.defaultManager + URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] + .lastObject.path.UTF8String); + return stderr_output.Append("stderr_output.txt"); +} + std::unique_ptr GetDatabase() { base::FilePath database_dir = GetDatabaseDir(); std::unique_ptr database = @@ -120,6 +134,14 @@ - (BOOL)application:(UIApplication*)application {"plat", "macOS"}, {"crashpad", "no"}}; } + + if ([arguments containsObject:@"--redirect-stderr-to-file"]) { + CHECK(freopen(GetStderrOutputFile().value().c_str(), "a", stderr) != + nullptr); + } else { + crashpad::test::RemoveFileIfExists(GetStderrOutputFile()); + } + if (client_.StartCrashpadInProcessHandler( GetDatabaseDir(), "", annotations)) { client_.ProcessIntermediateDumps(); @@ -265,7 +287,8 @@ - (void)crashException { } - (void)crashNSException { - // EDO has its own sinkhole, so dispatch this away. + // EDO has its own sinkhole which will suppress this attempt at an NSException + // crash, so dispatch this out of the sinkhole. dispatch_async(dispatch_get_main_queue(), ^{ NSError* error = [NSError errorWithDomain:@"com.crashpad.xcuitests" code:200 @@ -294,7 +317,8 @@ - (void)catchNSException { } - (void)crashCoreAutoLayoutSinkhole { - // EDO has its own sinkhole, so dispatch this away. + // EDO has its own sinkhole which will suppress this attempt at an NSException + // crash, so dispatch this out of the sinkhole. dispatch_async(dispatch_get_main_queue(), ^{ UIView* unattachedView = [[UIView alloc] init]; UIWindow* window = [UIApplication sharedApplication].windows[0]; @@ -354,4 +378,73 @@ - (void)crashWithAnnotations { abort(); } +class RaceThread : public crashpad::Thread { + public: + explicit RaceThread() : Thread() {} + + void SetCount(int count) { count_ = count; } + + private: + void ThreadMain() override { + for (int i = 0; i < count_; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + } + + int count_; +}; + +- (void)generateDumpWithoutCrash:(int)dump_count threads:(int)threads { + std::vector race_threads(threads); + for (RaceThread& race_thread : race_threads) { + race_thread.SetCount(dump_count); + race_thread.Start(); + } + + for (RaceThread& race_thread : race_threads) { + race_thread.Join(); + } +} + +class CrashThread : public crashpad::Thread { + public: + explicit CrashThread(bool signal) : Thread(), signal_(signal) {} + + private: + void ThreadMain() override { + sleep(1); + if (signal_) { + abort(); + } else { + __builtin_trap(); + } + } + bool signal_; +}; + +- (void)crashConcurrentSignalAndMach { + CrashThread signal_thread(true); + CrashThread mach_thread(false); + signal_thread.Start(); + mach_thread.Start(); + signal_thread.Join(); + mach_thread.Join(); +} + +- (void)crashInHandlerReentrant { + crashpad::CrashpadClient client_; + client_.SetMachExceptionCallbackForTesting(abort); + + // Trigger a Mach exception. + [self crashTrap]; +} + +- (NSString*)stderrContents { + NSString* path = + [NSString stringWithUTF8String:GetStderrOutputFile().value().c_str()]; + return [[NSString alloc] initWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:NULL]; +} + @end diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index 2fe36c556d..0c19bcaa03 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -91,6 +91,20 @@ // Trigger a crash after writing various annotations. - (void)crashWithAnnotations; +// Triggers a DumpWithoutCrash |dump_count| times in each of |threads| threads. +- (void)generateDumpWithoutCrash:(int)dump_count threads:(int)threads; + +// Triggers a simulataneous Mach exception and signal in different threads. +- (void)crashConcurrentSignalAndMach; + +// Triggers a SIGABRT signal while handling an NSException to test reentrant +// exceptions. +- (void)crashInHandlerReentrant; + +// Return the contents of the stderr file used when the host app is launch with +// the arguments --redirect-stderr-to-file +- (NSString*)stderrContents; + @end #endif // CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_ From 12b35ebde8699d49f3bbef7c82f55c334993aa00 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 8 Mar 2022 20:09:09 -0500 Subject: [PATCH 126/478] ios: Add forbidden allocator to integration tests. Override malloc_default_zone and malloc_default_purgeable_zone with allocators that exit when called from the signal or Mach exception threads in XCUITests, to verify the allocator is not used by the InProcessHandler. Check stderr for error messages to confirm failures. Change-Id: I1bb92e57504d71bbf6c6eaad3571c814e8a6934c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3488826 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/crashpad_client.h | 3 + client/crashpad_client_ios.cc | 8 + test/ios/crash_type_xctest.mm | 25 +- test/ios/host/BUILD.gn | 2 + test/ios/host/cptest_application_delegate.mm | 32 +- test/ios/host/cptest_shared_object.h | 17 +- test/ios/host/handler_forbidden_allocators.cc | 295 ++++++++++++++++++ test/ios/host/handler_forbidden_allocators.h | 31 ++ util/thread/thread.h | 8 + util/thread/thread_posix.cc | 10 + 10 files changed, 413 insertions(+), 18 deletions(-) create mode 100644 test/ios/host/handler_forbidden_allocators.cc create mode 100644 test/ios/host/handler_forbidden_allocators.h diff --git a/client/crashpad_client.h b/client/crashpad_client.h index c52f216c2d..1063dcf740 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -567,6 +567,9 @@ class CrashpadClient { //! \brief Inject a callback into Mach handling. Intended to be used by //! tests to trigger a reentrant exception. static void SetMachExceptionCallbackForTesting(void (*callback)()); + + //! \brief Returns the thread id of the Mach exception thread, used by tests. + static uint64_t GetThreadIdForTesting(); #endif #if BUILDFLAG(IS_APPLE) || DOXYGEN diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index b0e3c93e83..7a4f2a2d62 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -153,6 +153,8 @@ class CrashHandler : public Thread, in_process_handler_.SetMachExceptionCallbackForTesting(callback); } + uint64_t GetThreadIdForTesting() { return Thread::GetThreadIdForTesting(); } + private: CrashHandler() = default; @@ -423,4 +425,10 @@ void CrashpadClient::SetMachExceptionCallbackForTesting(void (*callback)()) { crash_handler->SetMachExceptionCallbackForTesting(callback); } +uint64_t CrashpadClient::GetThreadIdForTesting() { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + return crash_handler->GetThreadIdForTesting(); +} + } // namespace crashpad diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 46e3bd54ae..45d96310c5 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -103,6 +103,9 @@ - (void)verifyCrashReportException:(uint32_t)exception { NSNumber* report_exception; XCTAssertTrue([rootObject_ pendingReportException:&report_exception]); XCTAssertEqual(report_exception.unsignedIntValue, exception); + + NSString* stderrContents = [rootObject_ stderrContents]; + XCTAssertFalse([stderrContents containsString:@"allocator used in handler."]); } - (void)testEDO { @@ -322,8 +325,6 @@ - (void)testSimultaneousCrash { } - (void)testCrashInHandlerReentrant { - app_.launchArguments = @[ @"--redirect-stderr-to-file" ]; - [app_ launch]; XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); rootObject_ = [EDOClientService rootObjectWithPort:12345]; @@ -344,4 +345,24 @@ - (void)testCrashInHandlerReentrant { XCTAssertTrue([stderrContents containsString:errmsg]); } +- (void)testFailureWhenHandlerAllocates { + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + [rootObject_ allocateWithForbiddenAllocators]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + XCTAssertEqual([rootObject_ pendingReportCount], 0); + + NSString* stderrContents = [rootObject_ stderrContents]; + XCTAssertTrue([stderrContents containsString:@"allocator used in handler."]); +} + @end diff --git a/test/ios/host/BUILD.gn b/test/ios/host/BUILD.gn index 1c4e37518a..a5e04ee79f 100644 --- a/test/ios/host/BUILD.gn +++ b/test/ios/host/BUILD.gn @@ -35,6 +35,8 @@ static_library("app_host_sources") { "cptest_application_delegate.mm", "cptest_crash_view_controller.h", "cptest_crash_view_controller.mm", + "handler_forbidden_allocators.cc", + "handler_forbidden_allocators.h", "main.mm", ] configs += [ "../../..:crashpad_config" ] diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 4cfc5e2b77..5604732c88 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -42,6 +42,7 @@ #include "test/file.h" #import "test/ios/host/cptest_crash_view_controller.h" #import "test/ios/host/cptest_shared_object.h" +#import "test/ios/host/handler_forbidden_allocators.h" #include "util/file/filesystem.h" #include "util/thread/thread.h" @@ -113,6 +114,7 @@ OperationStatus GetPendingReports(std::vector* pending_reports) { @interface CPTestApplicationDelegate () - (void)processIntermediateDumps; +@property(copy, nonatomic) NSString* last_stderr_output; @end @implementation CPTestApplicationDelegate { @@ -135,12 +137,14 @@ - (BOOL)application:(UIApplication*)application {"crashpad", "no"}}; } - if ([arguments containsObject:@"--redirect-stderr-to-file"]) { - CHECK(freopen(GetStderrOutputFile().value().c_str(), "a", stderr) != - nullptr); - } else { - crashpad::test::RemoveFileIfExists(GetStderrOutputFile()); - } + NSString* path = + [NSString stringWithUTF8String:GetStderrOutputFile().value().c_str()]; + self.last_stderr_output = + [[NSString alloc] initWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:NULL]; + crashpad::test::RemoveFileIfExists(GetStderrOutputFile()); + CHECK(freopen(GetStderrOutputFile().value().c_str(), "a", stderr) != nullptr); if (client_.StartCrashpadInProcessHandler( GetDatabaseDir(), "", annotations)) { @@ -270,14 +274,17 @@ - (void)crashBadAccess [[clang::optnone]] { } - (void)crashKillAbort { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); kill(getpid(), SIGABRT); } - (void)crashTrap { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); __builtin_trap(); } - (void)crashAbort { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); abort(); } @@ -439,12 +446,15 @@ - (void)crashInHandlerReentrant { [self crashTrap]; } +- (void)allocateWithForbiddenAllocators { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); + (void)malloc(10); +} + - (NSString*)stderrContents { - NSString* path = - [NSString stringWithUTF8String:GetStderrOutputFile().value().c_str()]; - return [[NSString alloc] initWithContentsOfFile:path - encoding:NSUTF8StringEncoding - error:NULL]; + CPTestApplicationDelegate* delegate = + (CPTestApplicationDelegate*)UIApplication.sharedApplication.delegate; + return delegate.last_stderr_output; } @end diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index 0c19bcaa03..0041c580d1 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -55,13 +55,16 @@ // Triggers an EXC_BAD_ACCESS exception and crash. - (void)crashBadAccess; -// Triggers a crash with a call to kill(SIGABRT). +// Triggers a crash with a call to kill(SIGABRT). This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashKillAbort; -// Trigger a crash with a __builtin_trap. +// Trigger a crash with a __builtin_trap. This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashTrap; -// Trigger a crash with an abort(). +// Trigger a crash with an abort(). This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashAbort; // Trigger a crash with an uncaught exception. @@ -101,8 +104,12 @@ // exceptions. - (void)crashInHandlerReentrant; -// Return the contents of the stderr file used when the host app is launch with -// the arguments --redirect-stderr-to-file +// Runs with ReplaceAllocatorsWithHandlerForbidden and allocates memory, testing +// that the handler forbidden allocator works. +- (void)allocateWithForbiddenAllocators; + +// Return the contents of the stderr output from the previous run of the host +// application. - (NSString*)stderrContents; @end diff --git a/test/ios/host/handler_forbidden_allocators.cc b/test/ios/host/handler_forbidden_allocators.cc new file mode 100644 index 0000000000..dbb499a70c --- /dev/null +++ b/test/ios/host/handler_forbidden_allocators.cc @@ -0,0 +1,295 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "test/ios/host/handler_forbidden_allocators.h" + +#include +#include +#include +#include + +#include "base/mac/mach_logging.h" +#include "client/crashpad_client.h" +#include "util/ios/raw_logging.h" + +namespace crashpad { +namespace test { + +namespace { + +uint64_t g_main_thread = 0; +uint64_t g_mach_exception_thread = 0; +malloc_zone_t g_old_zone; + +bool is_handler_thread() { + uint64_t thread_self; + pthread_threadid_np(pthread_self(), &thread_self); + return (thread_self == g_main_thread || + thread_self == g_mach_exception_thread); +} + +void* handler_forbidden_malloc(struct _malloc_zone_t* zone, size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_malloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.malloc(zone, size); +} + +void* handler_forbidden_calloc(struct _malloc_zone_t* zone, + size_t num_items, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_calloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.calloc(zone, num_items, size); +} + +void* handler_forbidden_valloc(struct _malloc_zone_t* zone, size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_valloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.valloc(zone, size); +} + +void handler_forbidden_free(struct _malloc_zone_t* zone, void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_free allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.free(zone, ptr); +} + +void* handler_forbidden_realloc(struct _malloc_zone_t* zone, + void* ptr, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_realloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.realloc(zone, ptr, size); +} + +void handler_forbidden_destroy(struct _malloc_zone_t* zone) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_destroy allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.destroy(zone); +} + +void* handler_forbidden_memalign(struct _malloc_zone_t* zone, + size_t alignment, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_memalign allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.memalign(zone, alignment, size); +} + +unsigned handler_forbidden_batch_malloc(struct _malloc_zone_t* zone, + size_t size, + void** results, + unsigned num_requested) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_batch_malloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.batch_malloc(zone, size, results, num_requested); +} + +void handler_forbidden_batch_free(struct _malloc_zone_t* zone, + void** to_be_freed, + unsigned num_to_be_freed) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_batch_free allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.batch_free(zone, to_be_freed, num_to_be_freed); +} + +void handler_forbidden_free_definite_size(struct _malloc_zone_t* zone, + void* ptr, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_free_definite_size allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.free_definite_size(zone, ptr, size); +} + +size_t handler_forbidden_pressure_relief(struct _malloc_zone_t* zone, + size_t goal) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_pressure_relief allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.pressure_relief(zone, goal); +} + +boolean_t handler_forbidden_claimed_address(struct _malloc_zone_t* zone, + void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_claimed_address allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.claimed_address(zone, ptr); +} + +size_t handler_forbidden_size(struct _malloc_zone_t* zone, const void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_size allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.size(zone, ptr); +} + +bool DeprotectMallocZone(malloc_zone_t* default_zone, + vm_address_t* reprotection_start, + vm_size_t* reprotection_length, + vm_prot_t* reprotection_value) { + mach_port_t unused; + *reprotection_start = reinterpret_cast(default_zone); + struct vm_region_basic_info_64 info; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + kern_return_t result = vm_region_64(mach_task_self(), + reprotection_start, + reprotection_length, + VM_REGION_BASIC_INFO_64, + reinterpret_cast(&info), + &count, + &unused); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_region_64"; + return false; + } + + // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but + // balance it with a deallocate in case this ever changes. See + // the VM_REGION_BASIC_INFO_64 case in vm_map_region() in 10.15's + // https://opensource.apple.com/source/xnu/xnu-6153.11.26/osfmk/vm/vm_map.c . + mach_port_deallocate(mach_task_self(), unused); + + if (!(info.max_protection & VM_PROT_WRITE)) { + LOG(ERROR) << "Invalid max_protection " << info.max_protection; + return false; + } + + // Does the region fully enclose the zone pointers? Possibly unwarranted + // simplification used: using the size of a full version 10 malloc zone rather + // than the actual smaller size if the passed-in zone is not version 10. + DCHECK_LE(*reprotection_start, reinterpret_cast(default_zone)); + vm_size_t zone_offset = reinterpret_cast(default_zone) - + reinterpret_cast(*reprotection_start); + DCHECK_LE(zone_offset + sizeof(malloc_zone_t), *reprotection_length); + + if (info.protection & VM_PROT_WRITE) { + // No change needed; the zone is already writable. + *reprotection_start = 0; + *reprotection_length = 0; + *reprotection_value = VM_PROT_NONE; + } else { + *reprotection_value = info.protection; + result = vm_protect(mach_task_self(), + *reprotection_start, + *reprotection_length, + false, + info.protection | VM_PROT_WRITE); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_protect"; + return false; + } + } + return true; +} + +void ReplaceZoneFunctions(malloc_zone_t* zone, const malloc_zone_t* functions) { + // Remove protection. + vm_address_t reprotection_start = 0; + vm_size_t reprotection_length = 0; + vm_prot_t reprotection_value = VM_PROT_NONE; + bool success = DeprotectMallocZone( + zone, &reprotection_start, &reprotection_length, &reprotection_value); + if (!success) { + return; + } + + zone->size = functions->size; + zone->malloc = functions->malloc; + zone->calloc = functions->calloc; + zone->valloc = functions->valloc; + zone->free = functions->free; + zone->realloc = functions->realloc; + zone->destroy = functions->destroy; + zone->batch_malloc = functions->batch_malloc; + zone->batch_free = functions->batch_free; + zone->introspect = functions->introspect; + zone->memalign = functions->memalign; + zone->free_definite_size = functions->free_definite_size; + zone->pressure_relief = functions->pressure_relief; + zone->claimed_address = functions->claimed_address; + + // Restore protection if it was active. + if (reprotection_start) { + kern_return_t result = vm_protect(mach_task_self(), + reprotection_start, + reprotection_length, + false, + reprotection_value); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_protect"; + return; + } + } +} + +} // namespace + +void ReplaceAllocatorsWithHandlerForbidden() { + pthread_threadid_np(pthread_self(), &g_main_thread); + + CrashpadClient crashpad_client; + g_mach_exception_thread = crashpad_client.GetThreadIdForTesting(); + + malloc_zone_t* default_zone = malloc_default_zone(); + memcpy(&g_old_zone, default_zone, sizeof(g_old_zone)); + malloc_zone_t new_functions = {}; + new_functions.size = handler_forbidden_size; + new_functions.malloc = handler_forbidden_malloc; + new_functions.calloc = handler_forbidden_calloc; + new_functions.valloc = handler_forbidden_valloc; + new_functions.free = handler_forbidden_free; + new_functions.realloc = handler_forbidden_realloc; + new_functions.destroy = handler_forbidden_destroy; + new_functions.batch_malloc = handler_forbidden_batch_malloc; + new_functions.batch_free = handler_forbidden_batch_free; + new_functions.memalign = handler_forbidden_memalign; + new_functions.free_definite_size = handler_forbidden_free_definite_size; + new_functions.pressure_relief = handler_forbidden_pressure_relief; + new_functions.claimed_address = handler_forbidden_claimed_address; + ReplaceZoneFunctions(default_zone, &new_functions); + + malloc_zone_t* purgeable_zone = malloc_default_purgeable_zone(); + ReplaceZoneFunctions(purgeable_zone, &new_functions); +} + +} // namespace test +} // namespace crashpad diff --git a/test/ios/host/handler_forbidden_allocators.h b/test/ios/host/handler_forbidden_allocators.h new file mode 100644 index 0000000000..c32a092dea --- /dev/null +++ b/test/ios/host/handler_forbidden_allocators.h @@ -0,0 +1,31 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_ +#define CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_ + +namespace crashpad { +namespace test { + +// Override malloc_default_zone and malloc_default_purgeable_zone with functions +// that immediately exit if called from the same thread that this helper is +// called from or from the Crashpad Mach exception handler thread indicated by +// GetThreadIdForTesting. This is used to ensure the allocator is not used by +// the Crashpad InProcessHandler. +void ReplaceAllocatorsWithHandlerForbidden(); + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_ diff --git a/util/thread/thread.h b/util/thread/thread.h index 25fccb815a..6f93ed0961 100644 --- a/util/thread/thread.h +++ b/util/thread/thread.h @@ -19,10 +19,13 @@ #if BUILDFLAG(IS_POSIX) #include +#include #elif BUILDFLAG(IS_WIN) #include #endif // BUILDFLAG(IS_POSIX) +#include "build/build_config.h" + namespace crashpad { //! \brief Basic thread abstraction. Users should derive from this @@ -44,6 +47,11 @@ class Thread { //! Must paired with a call to Start(). void Join(); +#if BUILDFLAG(IS_APPLE) + //! \brief Returns the thread id of the Thread pthread_t. + uint64_t GetThreadIdForTesting(); +#endif // BUILDFLAG(IS_APPLE) + private: //! \brief The thread entry point to be implemented by the subclass. virtual void ThreadMain() = 0; diff --git a/util/thread/thread_posix.cc b/util/thread/thread_posix.cc index fe50050c7f..8e00c210c3 100644 --- a/util/thread/thread_posix.cc +++ b/util/thread/thread_posix.cc @@ -19,6 +19,7 @@ #include #include "base/check.h" +#include "build/build_config.h" namespace crashpad { @@ -35,6 +36,15 @@ void Thread::Join() { platform_thread_ = 0; } +#if BUILDFLAG(IS_APPLE) +uint64_t Thread::GetThreadIdForTesting() { + uint64_t thread_self; + errno = pthread_threadid_np(pthread_self(), &thread_self); + PCHECK(errno == 0) << "pthread_threadid_np"; + return thread_self; +} +#endif // BUILDFLAG(IS_APPLE) + // static void* Thread::ThreadEntryThunk(void* argument) { Thread* self = reinterpret_cast(argument); From 785cb10e80924f936eb32497248745a4726a540e Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 10 Mar 2022 14:12:57 -0500 Subject: [PATCH 127/478] ios: Move IOSSystemDataCollector to InProcessHandler. The IOSSystemDataCollector was previously owned by the iOS CrashHandler and passed in to the iOS InProcessHandler in each method. Move ownership to iOS InProcessHandler to simplify. Change-Id: Ifa41304cb1e3e3825a211e6cce5aa730d0edcc95 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3517965 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/crashpad_client_ios.cc | 25 ++++++------- client/ios_handler/in_process_handler.cc | 33 +++++++---------- client/ios_handler/in_process_handler.h | 35 +++++-------------- client/ios_handler/in_process_handler_test.cc | 3 +- 4 files changed, 32 insertions(+), 64 deletions(-) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 7a4f2a2d62..e98a232012 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -24,7 +24,6 @@ #include "base/mac/scoped_mach_port.h" #include "client/ios_handler/exception_processor.h" #include "client/ios_handler/in_process_handler.h" -#include "util/ios/ios_system_data_collector.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" @@ -74,8 +73,7 @@ class CrashHandler : public Thread, const std::string& url, const std::map& annotations) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - if (!in_process_handler_.Initialize( - database, url, annotations, system_data_) || + if (!in_process_handler_.Initialize(database, url, annotations) || !InstallMachExceptionHandler() || // xnu turns hardware faults into Mach exceptions, so the only signal // left to register is SIGABRT, which never starts off as a hardware @@ -128,8 +126,8 @@ class CrashHandler : public Thread, void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); base::FilePath path; - if (!in_process_handler_.DumpExceptionFromSimulatedMachException( - system_data_, context, &path)) { + if (!in_process_handler_.DumpExceptionFromSimulatedMachException(context, + &path)) { return; } @@ -140,8 +138,8 @@ class CrashHandler : public Thread, void DumpWithoutCrashAtPath(NativeCPUContext* context, const base::FilePath& path) { - in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath( - system_data_, context, path); + in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(context, + path); } void StartProcessingPendingReports() { @@ -278,8 +276,7 @@ class CrashHandler : public Thread, thread_state_flavor_t flavor, ConstThreadState old_state, mach_msg_type_number_t old_state_count) { - in_process_handler_.DumpExceptionFromMachException(system_data_, - behavior, + in_process_handler_.DumpExceptionFromMachException(behavior, thread, exception, code, @@ -291,8 +288,8 @@ class CrashHandler : public Thread, void HandleUncaughtNSException(const uint64_t* frames, const size_t num_frames) override { - in_process_handler_.DumpExceptionFromNSExceptionWithFrames( - system_data_, frames, num_frames); + in_process_handler_.DumpExceptionFromNSExceptionWithFrames(frames, + num_frames); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second // dump isn't generated. @@ -301,8 +298,7 @@ class CrashHandler : public Thread, void HandleUncaughtNSExceptionWithContext( NativeCPUContext* context) override { - in_process_handler_.DumpExceptionFromNSExceptionWithContext(system_data_, - context); + in_process_handler_.DumpExceptionFromNSExceptionWithContext(context); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -331,7 +327,7 @@ class CrashHandler : public Thread, siginfo_t* siginfo, ucontext_t* context, struct sigaction* old_action) { - in_process_handler_.DumpExceptionFromSignal(system_data_, siginfo, context); + in_process_handler_.DumpExceptionFromSignal(siginfo, context); // Always call system handler. Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action); @@ -341,7 +337,6 @@ class CrashHandler : public Thread, ExceptionPorts::ExceptionHandlerVector original_handlers_; struct sigaction old_action_ = {}; internal::InProcessHandler in_process_handler_; - internal::IOSSystemDataCollector system_data_; static CrashHandler* instance_; bool mach_handler_running_ = false; InitializationStateDcheck initialized_; diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index 2ed311311e..ffcbcebc85 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -71,8 +71,7 @@ InProcessHandler::~InProcessHandler() { bool InProcessHandler::Initialize( const base::FilePath& database, const std::string& url, - const std::map& annotations, - const IOSSystemDataCollector& system_data) { + const std::map& annotations) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); annotations_ = annotations; database_ = CrashReportDatabase::Initialize(database); @@ -80,7 +79,7 @@ bool InProcessHandler::Initialize( return false; } bundle_identifier_and_seperator_ = - system_data.BundleIdentifier() + kBundleSeperator; + system_data_.BundleIdentifier() + kBundleSeperator; if (!url.empty()) { // TODO(scottmg): options.rate_limit should be removed when we have a @@ -109,7 +108,7 @@ bool InProcessHandler::Initialize( PruneCondition::GetDefault(), base_dir_, bundle_identifier_and_seperator_, - system_data.IsExtension())); + system_data_.IsExtension())); prune_thread_->Start(); base::FilePath cached_writer_path = NewLockedFilePath(); @@ -126,10 +125,8 @@ bool InProcessHandler::Initialize( return true; } -void InProcessHandler::DumpExceptionFromSignal( - const IOSSystemDataCollector& system_data, - siginfo_t* siginfo, - ucontext_t* context) { +void InProcessHandler::DumpExceptionFromSignal(siginfo_t* siginfo, + ucontext_t* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); ScopedLockedWriter writer(GetCachedWriter(), cached_writer_path_.c_str(), @@ -138,13 +135,12 @@ void InProcessHandler::DumpExceptionFromSignal( CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer"); return; } - ScopedReport report(writer.GetWriter(), system_data, annotations_); + ScopedReport report(writer.GetWriter(), system_data_, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromSignal( - writer.GetWriter(), system_data, siginfo, context); + writer.GetWriter(), system_data_, siginfo, context); } void InProcessHandler::DumpExceptionFromMachException( - const IOSSystemDataCollector& system_data, exception_behavior_t behavior, thread_t thread, exception_type_t exception, @@ -166,7 +162,7 @@ void InProcessHandler::DumpExceptionFromMachException( mach_exception_callback_for_testing_(); } - ScopedReport report(writer.GetWriter(), system_data, annotations_); + ScopedReport report(writer.GetWriter(), system_data_, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromMachException( writer.GetWriter(), behavior, @@ -180,7 +176,6 @@ void InProcessHandler::DumpExceptionFromMachException( } void InProcessHandler::DumpExceptionFromNSExceptionWithContext( - const IOSSystemDataCollector& system_data, NativeCPUContext* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); // This does not use the cached writer. NSExceptionWithContext comes from @@ -198,7 +193,7 @@ void InProcessHandler::DumpExceptionFromNSExceptionWithContext( return; } - ScopedReport report(writer.GetWriter(), system_data, annotations_); + ScopedReport report(writer.GetWriter(), system_data_, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromMachException( writer.GetWriter(), MACH_EXCEPTION_CODES, @@ -212,7 +207,6 @@ void InProcessHandler::DumpExceptionFromNSExceptionWithContext( } void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( - const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); @@ -225,23 +219,20 @@ void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( return; } ScopedReport report( - writer.GetWriter(), system_data, annotations_, frames, num_frames); + writer.GetWriter(), system_data_, annotations_, frames, num_frames); InProcessIntermediateDumpHandler::WriteExceptionFromNSException( writer.GetWriter()); } bool InProcessHandler::DumpExceptionFromSimulatedMachException( - const IOSSystemDataCollector& system_data, const NativeCPUContext* context, base::FilePath* path) { base::FilePath locked_path = NewLockedFilePath(); *path = locked_path.RemoveFinalExtension(); - return DumpExceptionFromSimulatedMachExceptionAtPath( - system_data, context, locked_path); + return DumpExceptionFromSimulatedMachExceptionAtPath(context, locked_path); } bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( - const IOSSystemDataCollector& system_data, const NativeCPUContext* context, const base::FilePath& path) { // This does not use the cached writer. It's expected that simulated @@ -259,7 +250,7 @@ bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( "Cannot DumpExceptionFromSimulatedMachExceptionAtPath without writer"); return false; } - ScopedReport report(writer.GetWriter(), system_data, annotations_); + ScopedReport report(writer.GetWriter(), system_data_, annotations_); InProcessIntermediateDumpHandler::WriteExceptionFromMachException( writer.GetWriter(), MACH_EXCEPTION_CODES, diff --git a/client/ios_handler/in_process_handler.h b/client/ios_handler/in_process_handler.h index fe638452f3..096e477ca1 100644 --- a/client/ios_handler/in_process_handler.h +++ b/client/ios_handler/in_process_handler.h @@ -49,34 +49,28 @@ class InProcessHandler { //! \param[in] database The path to a Crashpad database. //! \param[in] url The URL of an upload server. //! \param[in] annotations Process annotations to set in each crash report. - //! \param[in] system_data An object containing various system data points. //! \return `true` if a handler to a pending intermediate dump could be //! opened. bool Initialize(const base::FilePath& database, const std::string& url, - const std::map& annotations, - const IOSSystemDataCollector& system_data); + const std::map& annotations); //! \brief Generate an intermediate dump from a signal handler exception. //! Writes the dump with the cached writer does not allow concurrent //! exceptions to be written. It is expected the system will terminate //! the application after this call. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal //! handler. //! \param[in] context A pointer to a `ucontext_t` object received by a //! signal. - void DumpExceptionFromSignal(const IOSSystemDataCollector& system_data, - siginfo_t* siginfo, - ucontext_t* context); + void DumpExceptionFromSignal(siginfo_t* siginfo, ucontext_t* context); //! \brief Generate an intermediate dump from a mach exception. Writes the //! dump with the cached writer does not allow concurrent exceptions to be //! written. It is expected the system will terminate the application //! after this call. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] behavior //! \param[in] thread //! \param[in] exception @@ -85,8 +79,7 @@ class InProcessHandler { //! \param[in,out] flavor //! \param[in] old_state //! \param[in] old_state_count - void DumpExceptionFromMachException(const IOSSystemDataCollector& system_data, - exception_behavior_t behavior, + void DumpExceptionFromMachException(exception_behavior_t behavior, thread_t thread, exception_type_t exception, const mach_exception_data_type_t* code, @@ -100,11 +93,8 @@ class InProcessHandler { //! exceptions is imperfect, uses a new writer for the intermediate dump, //! as it is possible for further exceptions to happen. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] context - void DumpExceptionFromNSExceptionWithContext( - const IOSSystemDataCollector& system_data, - NativeCPUContext* context); + void DumpExceptionFromNSExceptionWithContext(NativeCPUContext* context); //! \brief Generate an intermediate dump from an uncaught NSException. //! @@ -116,38 +106,30 @@ class InProcessHandler { //! the system will terminate the application after this call. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] frames An array of call stack frame addresses. //! \param[in] num_frames The number of frames in |frames|. - void DumpExceptionFromNSExceptionWithFrames( - const IOSSystemDataCollector& system_data, - const uint64_t* frames, - const size_t num_frames); + void DumpExceptionFromNSExceptionWithFrames(const uint64_t* frames, + const size_t num_frames); //! \brief Generate a simulated intermediate dump similar to a Mach exception //! in the same base directory as other exceptions. Does not use the //! cached writer. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] context A pointer to a NativeCPUContext object for this //! simulated exception. //! \param[out] path The path of the intermediate dump generated. //! \return `true` if the pending intermediate dump could be written. - bool DumpExceptionFromSimulatedMachException( - const IOSSystemDataCollector& system_data, - const NativeCPUContext* context, - base::FilePath* path); + bool DumpExceptionFromSimulatedMachException(const NativeCPUContext* context, + base::FilePath* path); //! \brief Generate a simulated intermediate dump similar to a Mach exception //! at a specific path. Does not use the cached writer. //! - //! \param[in] system_data An object containing various system data points. //! \param[in] context A pointer to a NativeCPUContext object for this //! simulated exception. //! \param[in] path Path to where the intermediate dump should be written. //! \return `true` if the pending intermediate dump could be written. bool DumpExceptionFromSimulatedMachExceptionAtPath( - const IOSSystemDataCollector& system_data, const NativeCPUContext* context, const base::FilePath& path); @@ -259,6 +241,7 @@ class InProcessHandler { std::unique_ptr prune_thread_; std::unique_ptr database_; std::string bundle_identifier_and_seperator_; + IOSSystemDataCollector system_data_; InitializationStateDcheck initialized_; }; diff --git a/client/ios_handler/in_process_handler_test.cc b/client/ios_handler/in_process_handler_test.cc index d7dfc05304..110d86c759 100644 --- a/client/ios_handler/in_process_handler_test.cc +++ b/client/ios_handler/in_process_handler_test.cc @@ -36,8 +36,7 @@ class InProcessHandlerTest : public testing::Test { // testing::Test: void SetUp() override { - ASSERT_TRUE( - in_process_handler_.Initialize(temp_dir_.path(), "", {}, system_data_)); + ASSERT_TRUE(in_process_handler_.Initialize(temp_dir_.path(), "", {})); pending_dir_ = temp_dir_.path().Append("pending-serialized-ios-dump"); bundle_identifier_and_seperator_ = system_data_.BundleIdentifier() + "@"; } From ab43d794a6812609803a0bf30838e72cce8b85c4 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 10 Mar 2022 13:27:13 -0700 Subject: [PATCH 128/478] win: Use `RegQueryValueExW()` instead of `RegQueryValueEx()` crrev.com/c/3434090 introduced a change that breaks the Windows build when the `UNICODE` preprocessor macro is not defined, as it passed a `wchar_t*` to `RegQueryValueEx()`. This fixes the build by explicitly using `RegQueryValueExW()` instead. Change-Id: Ic438bd982fdeffba05b4224051242b45e797ebd8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3516536 Reviewed-by: Joshua Peraza Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- snapshot/win/system_snapshot_win.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index ba1c1e7532..6fc69458fb 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -76,12 +76,12 @@ bool ReadRegistryDWORD(HKEY key, const wchar_t* name, int* out_value) { DWORD type; DWORD local_value; DWORD size = sizeof(local_value); - if (RegQueryValueEx(key, - name, - nullptr, - &type, - reinterpret_cast(&local_value), - &size) == ERROR_SUCCESS && + if (RegQueryValueExW(key, + name, + nullptr, + &type, + reinterpret_cast(&local_value), + &size) == ERROR_SUCCESS && type == REG_DWORD) { *out_value = static_cast(local_value); return true; From 9476a76dc093adab164bdc2951fda0fbb85abe47 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 10 Mar 2022 14:35:02 -0700 Subject: [PATCH 129/478] win: Use RegOpenKeyExW() instead of RegOpenKeyEx() Similar to crrev.com/c/3516536, this CL fixes the Windows build when the UNICODE preprocessor macro is not defined where code passes Unicode string literals with L"..." to non-Unicode APIs like RegOpenKeyEx(). This fixes the build by explicitly using RegOpenKeyExW() instead. Change-Id: I14a827357b9cbd42452e0e5eb13a3430569559a5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3516538 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- snapshot/win/system_snapshot_win.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index 6fc69458fb..a19253f23b 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -158,11 +158,11 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { bool version_data_found = false; int os_version_build = 0; HKEY key; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", - 0, - KEY_QUERY_VALUE, - &key) == ERROR_SUCCESS) { + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + 0, + KEY_QUERY_VALUE, + &key) == ERROR_SUCCESS) { ScopedRegistryKey scoped_key(key); // Read the four components of the version from the registry. @@ -282,11 +282,11 @@ std::string SystemSnapshotWin::CPUVendor() const { #elif defined(ARCH_CPU_ARM64) HKEY key; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", - 0, - KEY_QUERY_VALUE, - &key) != ERROR_SUCCESS) { + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + 0, + KEY_QUERY_VALUE, + &key) != ERROR_SUCCESS) { return std::string(); } From 9c1719802f6f68946ad856533238df826075dc27 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 15 Mar 2022 12:57:26 -0400 Subject: [PATCH 130/478] ios: Replace RawLog FileHandler instead of using freopen for tests. Previous commits[1][2] modified tests to require looking at RawLog output to validate the success or failure of the iOS InHandlerProcess. Previously this would use freopen to direct the RawLog to a file. However, freopen introduces a race where the log file may not be associated with stderr, and instead may interfere with the InProcessHandler's cached writer fd. This caused flake with the intermediate dumps sometimes including stderr logging. Since the test fixtures only needs to know about the output of RawLog, instead add a crashpad::internal::SetFileHandleForTesting method to that swaps out STDERR_FILENO with the test fixture's fd. [1] https://crrev.com/c/3488826 [2] https://crrev.com/c/3401563 Change-Id: I87b1020db6b896a47bec5a7c916a572c192b884f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3517773 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- test/ios/crash_type_xctest.mm | 12 +++--- test/ios/host/cptest_application_delegate.mm | 44 +++++++++++--------- test/ios/host/cptest_shared_object.h | 4 +- util/ios/raw_logging.cc | 20 +++++++-- util/ios/raw_logging.h | 7 ++++ 5 files changed, 55 insertions(+), 32 deletions(-) diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 45d96310c5..9f41c5eaf9 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -104,8 +104,8 @@ - (void)verifyCrashReportException:(uint32_t)exception { XCTAssertTrue([rootObject_ pendingReportException:&report_exception]); XCTAssertEqual(report_exception.unsignedIntValue, exception); - NSString* stderrContents = [rootObject_ stderrContents]; - XCTAssertFalse([stderrContents containsString:@"allocator used in handler."]); + NSString* rawLogContents = [rootObject_ rawLogContents]; + XCTAssertFalse([rawLogContents containsString:@"allocator used in handler."]); } - (void)testEDO { @@ -340,9 +340,9 @@ - (void)testCrashInHandlerReentrant { XCTAssertEqual([rootObject_ pendingReportCount], 0); - NSString* stderrContents = [rootObject_ stderrContents]; + NSString* rawLogContents = [rootObject_ rawLogContents]; NSString* errmsg = @"Cannot DumpExceptionFromSignal without writer"; - XCTAssertTrue([stderrContents containsString:errmsg]); + XCTAssertTrue([rawLogContents containsString:errmsg]); } - (void)testFailureWhenHandlerAllocates { @@ -361,8 +361,8 @@ - (void)testFailureWhenHandlerAllocates { XCTAssertEqual([rootObject_ pendingReportCount], 0); - NSString* stderrContents = [rootObject_ stderrContents]; - XCTAssertTrue([stderrContents containsString:@"allocator used in handler."]); + NSString* rawLogContents = [rootObject_ rawLogContents]; + XCTAssertTrue([rawLogContents containsString:@"allocator used in handler."]); } @end diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 5604732c88..2573324ab4 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -44,6 +44,7 @@ #import "test/ios/host/cptest_shared_object.h" #import "test/ios/host/handler_forbidden_allocators.h" #include "util/file/filesystem.h" +#include "util/ios/raw_logging.h" #include "util/thread/thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -63,12 +64,12 @@ return database_dir.Append("crashpad"); } -base::FilePath GetStderrOutputFile() { - base::FilePath stderr_output([NSFileManager.defaultManager - URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask] - .lastObject.path.UTF8String); - return stderr_output.Append("stderr_output.txt"); +base::FilePath GetRawLogOutputFile() { + base::FilePath document_directory([NSFileManager.defaultManager + URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] + .lastObject.path.UTF8String); + return document_directory.Append("raw_log_output.txt"); } std::unique_ptr GetDatabase() { @@ -114,21 +115,34 @@ OperationStatus GetPendingReports(std::vector* pending_reports) { @interface CPTestApplicationDelegate () - (void)processIntermediateDumps; -@property(copy, nonatomic) NSString* last_stderr_output; +@property(copy, nonatomic) NSString* raw_log_output; @end @implementation CPTestApplicationDelegate { crashpad::CrashpadClient client_; + crashpad::ScopedFileHandle raw_logging_file_; } @synthesize window = _window; - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + base::FilePath raw_log_file_path = GetRawLogOutputFile(); + NSString* path = + [NSString stringWithUTF8String:raw_log_file_path.value().c_str()]; + self.raw_log_output = + [[NSString alloc] initWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:NULL]; + raw_logging_file_.reset( + LoggingOpenFileForWrite(raw_log_file_path, + crashpad::FileWriteMode::kTruncateOrCreate, + crashpad::FilePermissions::kOwnerOnly)); + crashpad::internal::SetFileHandleForTesting(raw_logging_file_.get()); + // Start up crashpad. std::map annotations = { {"prod", "xcuitest"}, {"ver", "1"}, {"plat", "iOS"}, {"crashpad", "yes"}}; - NSArray* arguments = [[NSProcessInfo processInfo] arguments]; if ([arguments containsObject:@"--alternate-client-annotations"]) { annotations = {{"prod", "some_app"}, @@ -136,16 +150,6 @@ - (BOOL)application:(UIApplication*)application {"plat", "macOS"}, {"crashpad", "no"}}; } - - NSString* path = - [NSString stringWithUTF8String:GetStderrOutputFile().value().c_str()]; - self.last_stderr_output = - [[NSString alloc] initWithContentsOfFile:path - encoding:NSUTF8StringEncoding - error:NULL]; - crashpad::test::RemoveFileIfExists(GetStderrOutputFile()); - CHECK(freopen(GetStderrOutputFile().value().c_str(), "a", stderr) != nullptr); - if (client_.StartCrashpadInProcessHandler( GetDatabaseDir(), "", annotations)) { client_.ProcessIntermediateDumps(); @@ -451,10 +455,10 @@ - (void)allocateWithForbiddenAllocators { (void)malloc(10); } -- (NSString*)stderrContents { +- (NSString*)rawLogContents { CPTestApplicationDelegate* delegate = (CPTestApplicationDelegate*)UIApplication.sharedApplication.delegate; - return delegate.last_stderr_output; + return delegate.raw_log_output; } @end diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index 0041c580d1..a43e5445e2 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -108,9 +108,9 @@ // that the handler forbidden allocator works. - (void)allocateWithForbiddenAllocators; -// Return the contents of the stderr output from the previous run of the host +// Return the contents of the RawLog output from the previous run of the host // application. -- (NSString*)stderrContents; +- (NSString*)rawLogContents; @end diff --git a/util/ios/raw_logging.cc b/util/ios/raw_logging.cc index f037c45289..821348e5b8 100644 --- a/util/ios/raw_logging.cc +++ b/util/ios/raw_logging.cc @@ -14,6 +14,8 @@ #include "util/ios/raw_logging.h" +#include + #include #include #include @@ -23,12 +25,22 @@ namespace crashpad { namespace internal { +namespace { +static_assert(std::atomic::is_always_lock_free, + "std::atomic may not be signal-safe"); +std::atomic g_file_handle = STDERR_FILENO; +} // namespace + +void SetFileHandleForTesting(FileHandle file_handle) { + g_file_handle = file_handle; +} + void RawLogString(const char* message) { const size_t message_len = strlen(message); size_t bytes_written = 0; while (bytes_written < message_len) { int rv = HANDLE_EINTR(write( - STDERR_FILENO, message + bytes_written, message_len - bytes_written)); + g_file_handle, message + bytes_written, message_len - bytes_written)); if (rv < 0) { // Give up, nothing we can do now. break; @@ -51,15 +63,15 @@ void RawLogInt(unsigned int number) { // Prints `path:linenum message:error` (with optional `:error`). void RawLog(const char* file, int line, const char* message, int error) { RawLogString(file); - HANDLE_EINTR(write(STDERR_FILENO, ":", 1)); + HANDLE_EINTR(write(g_file_handle, ":", 1)); RawLogInt(line); - HANDLE_EINTR(write(STDERR_FILENO, " ", 1)); + HANDLE_EINTR(write(g_file_handle, " ", 1)); RawLogString(message); if (error) { RawLogString(": "); RawLogInt(error); } - HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); + HANDLE_EINTR(write(g_file_handle, "\n", 1)); } } // namespace internal diff --git a/util/ios/raw_logging.h b/util/ios/raw_logging.h index 6075281713..16f08d601d 100644 --- a/util/ios/raw_logging.h +++ b/util/ios/raw_logging.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_UTIL_IOS_EXCEPTION_LOGGING_H_ #define CRASHPAD_UTIL_IOS_EXCEPTION_LOGGING_H_ +#include "util/file/file_io.h" + namespace crashpad { namespace internal { @@ -25,6 +27,11 @@ namespace internal { //! Note: RUNS-DURING-CRASH. void RawLog(const char* file, int line, const char* message, int error); +//! \brief Direct RawLog to log to \a file_handle instead of stderr, so tests +//! can confirm certain error conditions during in-process crashes. Call +//! before before any Crashpad is run. +void SetFileHandleForTesting(FileHandle file_handle); + } // namespace internal } // namespace crashpad From cd13ea34ebca8f993d4d60fa40dc7fde3a95bee3 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 14 Mar 2022 11:03:06 -0400 Subject: [PATCH 131/478] ios: Add ScopedBackgroundTask to UploadThread and PruneThread. iOS applications may be terminated with the exception code 0xdead10cc when holding on to file locks in the shared container during suspension. One approach to minimize this is to request additional background execution time to complete the locking operation (in this case the CrashReportUpload thread and the PruneIntermediateDumpsAndCrashReports thread). Bug: crashpad:400 Change-Id: I4192ae1a92646ea337a09ac071e49761ab2d3860 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3517966 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- ...rmediate_dumps_and_crash_reports_thread.cc | 2 + handler/crash_report_upload_thread.cc | 10 +++- util/BUILD.gn | 8 ++- util/ios/scoped_background_task.h | 40 +++++++++++++ util/ios/scoped_background_task.mm | 58 +++++++++++++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 util/ios/scoped_background_task.h create mode 100644 util/ios/scoped_background_task.mm diff --git a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc index d6cfe885d2..1b7977cf47 100644 --- a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc +++ b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc @@ -19,6 +19,7 @@ #include "client/prune_crash_reports.h" #include "util/file/directory_reader.h" #include "util/file/filesystem.h" +#include "util/ios/scoped_background_task.h" namespace crashpad { @@ -115,6 +116,7 @@ void PruneIntermediateDumpsAndCrashReportsThread::Stop() { void PruneIntermediateDumpsAndCrashReportsThread::DoWork( const WorkerThread* thread) { + internal::ScopedBackgroundTask scoper("PruneThread"); database_->CleanDatabase(60 * 60 * 24 * 3); PruneCrashReportDatabase(database_, condition_.get()); if (!clean_old_intermediate_dumps_) { diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index c691361494..efbeab7804 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -44,6 +44,10 @@ #include "handler/mac/file_limit_annotation.h" #endif // BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_IOS) +#include "util/ios/scoped_background_task.h" +#endif // BUILDFLAG(IS_IOS) + namespace crashpad { namespace { @@ -97,6 +101,10 @@ void CrashReportUploadThread::Stop() { } void CrashReportUploadThread::ProcessPendingReports() { +#if BUILDFLAG(IS_IOS) + internal::ScopedBackgroundTask scoper("CrashReportUploadThread"); +#endif // BUILDFLAG(IS_IOS) + std::vector known_report_uuids = known_pending_report_uuids_.Drain(); for (const UUID& report_uuid : known_report_uuids) { CrashReportDatabase::Report report; @@ -175,7 +183,7 @@ void CrashReportUploadThread::ProcessPendingReport( #if BUILDFLAG(IS_IOS) if (ShouldRateLimitRetry(report)) return; -#endif +#endif // BUILDFLAG(IS_IOS) std::unique_ptr upload_report; CrashReportDatabase::OperationStatus status = diff --git a/util/BUILD.gn b/util/BUILD.gn index d5e63d2dff..435d035731 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -385,6 +385,8 @@ crashpad_static_library("util") { "ios/ios_system_data_collector.mm", "ios/raw_logging.cc", "ios/raw_logging.h", + "ios/scoped_background_task.h", + "ios/scoped_background_task.mm", "ios/scoped_vm_read.cc", "ios/scoped_vm_read.h", ] @@ -466,9 +468,9 @@ crashpad_static_library("util") { "win/context_wrappers.h", "win/critical_section_with_debug_info.cc", "win/critical_section_with_debug_info.h", + "win/exception_codes.h", "win/exception_handler_server.cc", "win/exception_handler_server.h", - "win/exception_codes.h", "win/get_function.cc", "win/get_function.h", "win/get_module_information.cc", @@ -583,6 +585,10 @@ crashpad_static_library("util") { deps += [ ":mig_output" ] } + if (crashpad_is_ios) { + deps += [ "../build:ios_enable_arc" ] + } + if (crashpad_is_mac && !crashpad_is_in_fuchsia) { libs = [ "bsm" ] frameworks = [ diff --git a/util/ios/scoped_background_task.h b/util/ios/scoped_background_task.h new file mode 100644 index 0000000000..909915b757 --- /dev/null +++ b/util/ios/scoped_background_task.h @@ -0,0 +1,40 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_IOS_SCOPED_BACKGROUND_TASK_H_ +#define CRASHPAD_UTIL_IOS_SCOPED_BACKGROUND_TASK_H_ + +#include + +namespace crashpad { +namespace internal { + +//! \brief Marks the start of a task that should continue if the application +//! enters the background. +class ScopedBackgroundTask { + public: + //! \param[in] task_name A string used in debugging to indicate the reason the + //! activity began. This parameter must not be nullptr or an empty string. + ScopedBackgroundTask(const char* task_name); + + ScopedBackgroundTask(const ScopedBackgroundTask&) = delete; + ScopedBackgroundTask& operator=(const ScopedBackgroundTask&) = delete; + ~ScopedBackgroundTask(); + + private: + dispatch_semaphore_t task_complete_semaphore_; +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_UTIL_IOS_SCOPED_BACKGROUND_TASK_H_ diff --git a/util/ios/scoped_background_task.mm b/util/ios/scoped_background_task.mm new file mode 100644 index 0000000000..fdf2640e2e --- /dev/null +++ b/util/ios/scoped_background_task.mm @@ -0,0 +1,58 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/ios/scoped_background_task.h" + +#import + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace crashpad { +namespace internal { + +ScopedBackgroundTask::ScopedBackgroundTask(const char* task_name) + : task_complete_semaphore_(dispatch_semaphore_create(0)) { + __weak dispatch_semaphore_t weak_task_complete_semaphore = + task_complete_semaphore_; + NSString* name = [NSString stringWithUTF8String:task_name]; + [[NSProcessInfo processInfo] + performExpiringActivityWithReason:name + usingBlock:^(BOOL expired) { + if (expired) { + // TODO(crbug.com/crashpad/400): Notify the + // BG task creator that time's up -- this will + // be useful for BackgroundTasks and + // NSURLSessions. + return; + } + __strong dispatch_semaphore_t + strong_task_complete_semaphore = + weak_task_complete_semaphore; + if (!strong_task_complete_semaphore) { + return; + } + dispatch_semaphore_wait( + strong_task_complete_semaphore, + DISPATCH_TIME_FOREVER); + }]; +} + +ScopedBackgroundTask::~ScopedBackgroundTask() { + dispatch_semaphore_signal(task_complete_semaphore_); +} + +} // namespace internal +} // namespace crashpad From 4c85c466b00cb762cefae816fbfab5c968aec25c Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 15 Mar 2022 20:10:09 -0400 Subject: [PATCH 132/478] ios: Fix test failure on M1 ARM64 machines. in_process_intermediate_dump_handler_test was mixing CPU architecture (x86_64 vs arm64) and iOS device type (iphoneos vs iphonesimulator). Bug: 1306589 Change-Id: Ie43a7f1916d69888e992320d999010071b2575b3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3527034 Reviewed-by: Rohit Rao Commit-Queue: Justin Cohen --- .../in_process_intermediate_dump_handler_test.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/client/ios_handler/in_process_intermediate_dump_handler_test.cc index 54af2c7f0d..e61a604d9d 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler_test.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler_test.cc @@ -104,12 +104,18 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestSystem) { EXPECT_STREQ(system->CPUVendor().c_str(), "GenuineIntel"); #elif defined(ARCH_CPU_ARM64) EXPECT_EQ(system->GetCPUArchitecture(), kCPUArchitectureARM64); +#else +#error Port to your CPU architecture +#endif +#if TARGET_OS_SIMULATOR + EXPECT_EQ(system->MachineDescription().substr(0, 13), + std::string("iOS Simulator")); +#elif TARGET_OS_IPHONE utsname uts; ASSERT_EQ(uname(&uts), 0); EXPECT_STREQ(system->MachineDescription().c_str(), uts.machine); -#else -#error Port to your CPU architecture #endif + EXPECT_EQ(system->GetOperatingSystem(), SystemSnapshot::kOperatingSystemIOS); } From 460dbdceaeb46eb6744077eb5fd6209d3b5143f8 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 22 Mar 2022 14:02:22 -0400 Subject: [PATCH 133/478] ios: Unblock all signals corresponding to Mach exceptions on crash. https://crrev.com/c/3401563 introduced logic to guard the cached intermediate dump writer from concurrent exceptions with a first exception wins approach. To prevent the losing exception from returning immediately and terminating the app before the dump is written, the losing thread sleeps indefinitely. In the case where the losing exception is from a call to abort() and the winning exception is a Mach exception, the process will never terminate because abort() will first block all signals on all other threads with a sigprocmask. This prevents the kernel from delivering the signal converted from the Mach exception and will never terminate. This effectively deadlocks the app. Instead, unblock all signals corresponding to all Mach exceptions Crashpad registers for before returning KERN_FAILURE. Bug: crashpad:391 Change-Id: I96c357e98f09e65e70c67125a45b9b04075c2c06 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3518186 Reviewed-by: Mark Mentovai Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/crashpad_client_ios.cc | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index e98a232012..af9524ef35 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -14,6 +14,7 @@ #include "client/crashpad_client.h" +#include #include #include @@ -24,6 +25,7 @@ #include "base/mac/scoped_mach_port.h" #include "client/ios_handler/exception_processor.h" #include "client/ios_handler/in_process_handler.h" +#include "util/ios/raw_logging.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" @@ -249,8 +251,7 @@ class CrashHandler : public Thread, // inherit the task exception ports, and this process isn’t prepared to // handle them if (task != mach_task_self()) { - LOG(WARNING) << "task 0x" << std::hex << task << " != 0x" - << mach_task_self(); + CRASHPAD_RAW_LOG("MachException task != mach_task_self()"); return KERN_FAILURE; } @@ -264,7 +265,31 @@ class CrashHandler : public Thread, old_state_count); // Respond with KERN_FAILURE so the system will continue to handle this - // exception as a crash. + // exception. xnu will turn this Mach exception into a signal and take the + // default action to terminate the process. However, if sigprocmask is + // called before this Mach exception returns (such as by another thread + // calling abort, see: Libc-1506.40.4/stdlib/FreeBSD/abort.c), the Mach + // exception will be converted into a signal but delivery will be blocked. + // Since concurrent exceptions lead to the losing thread sleeping + // indefinitely, if the abort thread never returns, the thread that + // triggered this Mach exception will repeatedly trap and the process will + // never terminate. If the abort thread didn’t have a user-space signal + // handler that slept forever, the abort would terminate the process even if + // all other signals had been blocked. Instead, unblock all signals + // corresponding to all Mach exceptions Crashpad is registered for before + // returning KERN_FAILURE. There is still racy behavior possible with this + // call to sigprocmask, but the repeated calls to CatchMachException here + // will eventually lead to termination. + sigset_t unblock_set; + sigemptyset(&unblock_set); + sigaddset(&unblock_set, SIGILL); // EXC_BAD_INSTRUCTION + sigaddset(&unblock_set, SIGTRAP); // EXC_BREAKPOINT + sigaddset(&unblock_set, SIGFPE); // EXC_ARITHMETIC + sigaddset(&unblock_set, SIGBUS); // EXC_BAD_ACCESS + sigaddset(&unblock_set, SIGSEGV); // EXC_BAD_ACCESS + if (sigprocmask(SIG_UNBLOCK, &unblock_set, nullptr) != 0) { + CRASHPAD_RAW_LOG("sigprocmask"); + } return KERN_FAILURE; } From 243dffb04573a66a0c0a3915c6cefaf978adb95d Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 22 Mar 2022 22:37:00 -0400 Subject: [PATCH 134/478] ios: Stop prune and upload thread when app is inactive and may suspend. Stop the prune thread and the upload thread when moving to the inactive/background state. This will reduce the number of 0xdead10cc system kills from having a file lock during iOS suspend. Wait to start the prune thread when the application is active. Otherwise, for iOS prewarmed applications, the prune thread will regularly start when the application is foregrounded for the first time when the user intentionally runs the app. It's still possible for either the prune thread or the upload thread to have a file lock during iOS suspend, such as when a task started in the foreground and does not complete in time for suspension. Future work should include considering BackgroundTasks and/or NSURLSessions, which can more safely run in the background. Bug: crashpad: 400 Change-Id: Ic7d4687eb795fe585327f128aa84a5928141f4a9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3517967 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/ios_handler/in_process_handler.cc | 42 ++++++++-- client/ios_handler/in_process_handler.h | 8 +- ...rmediate_dumps_and_crash_reports_thread.cc | 22 ++++- ...ermediate_dumps_and_crash_reports_thread.h | 4 + handler/crash_report_upload_thread.h | 3 + util/ios/ios_system_data_collector.h | 28 +++---- util/ios/ios_system_data_collector.mm | 82 +++++++++++-------- 7 files changed, 129 insertions(+), 60 deletions(-) diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index ffcbcebc85..0642884d08 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -62,10 +62,7 @@ namespace internal { InProcessHandler::InProcessHandler() = default; InProcessHandler::~InProcessHandler() { - if (upload_thread_started_ && upload_thread_) { - upload_thread_->Stop(); - } - prune_thread_->Stop(); + UpdatePruneAndUploadThreads(false); } bool InProcessHandler::Initialize( @@ -103,13 +100,20 @@ bool InProcessHandler::Initialize( if (!CreateDirectory(base_dir_)) return false; + bool is_app_extension = system_data_.IsExtension(); prune_thread_.reset(new PruneIntermediateDumpsAndCrashReportsThread( database_.get(), PruneCondition::GetDefault(), base_dir_, bundle_identifier_and_seperator_, - system_data_.IsExtension())); - prune_thread_->Start(); + is_app_extension)); + if (is_app_extension || system_data_.IsApplicationActive()) + prune_thread_->Start(); + + if (!is_app_extension) { + system_data_.SetActiveApplicationCallback( + [this](bool active) { UpdatePruneAndUploadThreads(active); }); + } base::FilePath cached_writer_path = NewLockedFilePath(); cached_writer_ = CreateWriterWithPath(cached_writer_path); @@ -284,9 +288,29 @@ void InProcessHandler::ProcessIntermediateDump( } void InProcessHandler::StartProcessingPendingReports() { - if (!upload_thread_started_ && upload_thread_) { - upload_thread_->Start(); - upload_thread_started_ = true; + if (!upload_thread_) + return; + + upload_thread_enabled_ = true; + UpdatePruneAndUploadThreads(true); +} + +void InProcessHandler::UpdatePruneAndUploadThreads(bool active) { + base::AutoLock lock_owner(prune_and_upload_lock_); + // TODO(crbug.com/crashpad/400): Consider moving prune and upload thread to + // BackgroundTasks and/or NSURLSession. This might allow uploads to continue + // in the background. + if (active) { + if (!prune_thread_->is_running()) + prune_thread_->Start(); + if (upload_thread_enabled_ && !upload_thread_->is_running()) { + upload_thread_->Start(); + } + } else { + if (prune_thread_->is_running()) + prune_thread_->Stop(); + if (upload_thread_enabled_ && upload_thread_->is_running()) + upload_thread_->Stop(); } } diff --git a/client/ios_handler/in_process_handler.h b/client/ios_handler/in_process_handler.h index 096e477ca1..f551b90d9d 100644 --- a/client/ios_handler/in_process_handler.h +++ b/client/ios_handler/in_process_handler.h @@ -21,6 +21,7 @@ #include #include "base/files/file_path.h" +#include "base/synchronization/lock.h" #include "client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h" #include "handler/crash_report_upload_thread.h" #include "snapshot/ios/process_snapshot_ios_intermediate_dump.h" @@ -202,6 +203,9 @@ class InProcessHandler { IOSIntermediateDumpWriter* writer_; }; + //! \brief Manage the prune and upload thread when the active state changes. + void UpdatePruneAndUploadThreads(bool active); + //! \brief Writes a minidump to the Crashpad database from the //! \a process_snapshot, and triggers the upload_thread_ if started. void SaveSnapshot(ProcessSnapshotIOSIntermediateDump& process_snapshot); @@ -230,7 +234,9 @@ class InProcessHandler { // in DumpExceptionFromMachException after aquiring the cached_writer_. void (*mach_exception_callback_for_testing_)() = nullptr; - bool upload_thread_started_ = false; + // Used to synchronize access to UpdatePruneAndUploadThreads(). + base::Lock prune_and_upload_lock_; + std::atomic_bool upload_thread_enabled_ = false; std::map annotations_; base::FilePath base_dir_; std::string cached_writer_path_; diff --git a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc index 1b7977cf47..651b390775 100644 --- a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc +++ b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.cc @@ -28,6 +28,9 @@ namespace { // The file extension used to indicate a file is locked. constexpr char kLockedExtension[] = ".locked"; +// Prune onces a day. +constexpr time_t prune_interval = 60 * 60 * 24; + // If the client finds a locked file matching it's own bundle id, unlock it // after 24 hours. constexpr time_t matching_bundle_locked_ttl = 60 * 60 * 24; @@ -96,11 +99,12 @@ PruneIntermediateDumpsAndCrashReportsThread:: base::FilePath pending_path, std::string bundle_identifier_and_seperator, bool is_extension) - : thread_(60 * 60 * 24, this), + : thread_(prune_interval, this), condition_(std::move(condition)), pending_path_(pending_path), bundle_identifier_and_seperator_(bundle_identifier_and_seperator), initial_work_delay_(is_extension ? extension_delay : app_delay), + last_start_time_(0), database_(database) {} PruneIntermediateDumpsAndCrashReportsThread:: @@ -116,9 +120,25 @@ void PruneIntermediateDumpsAndCrashReportsThread::Stop() { void PruneIntermediateDumpsAndCrashReportsThread::DoWork( const WorkerThread* thread) { + // This thread may be stopped and started a number of times throughout the + // lifetime of the process to prevent 0xdead10cc kills (see + // crbug.com/crashpad/400), but it should only run once per prune_interval + // after initial_work_delay_. + time_t now = time(nullptr); + if (now - last_start_time_ < prune_interval) + return; + last_start_time_ = now; + internal::ScopedBackgroundTask scoper("PruneThread"); database_->CleanDatabase(60 * 60 * 24 * 3); + + // Here and below, respect Stop() being called after each task. + if (!thread_.is_running()) + return; PruneCrashReportDatabase(database_, condition_.get()); + + if (!thread_.is_running()) + return; if (!clean_old_intermediate_dumps_) { clean_old_intermediate_dumps_ = true; UnlockOldIntermediateDumps(pending_path_, bundle_identifier_and_seperator_); diff --git a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h index b2764234c3..cc40980d50 100644 --- a/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h +++ b/client/ios_handler/prune_intermediate_dumps_and_crash_reports_thread.h @@ -84,6 +84,9 @@ class PruneIntermediateDumpsAndCrashReportsThread //! It is expected to only be called from the same thread that called Start(). void Stop() override; + //! \return `true` if the thread is running, `false` if it is not. + bool is_running() const { return thread_.is_running(); } + private: // WorkerThread::Delegate: void DoWork(const WorkerThread* thread) override; @@ -94,6 +97,7 @@ class PruneIntermediateDumpsAndCrashReportsThread std::string bundle_identifier_and_seperator_; bool clean_old_intermediate_dumps_; double initial_work_delay_; + time_t last_start_time_; CrashReportDatabase* database_; // weak }; diff --git a/handler/crash_report_upload_thread.h b/handler/crash_report_upload_thread.h index 70f1628354..2af958d7da 100644 --- a/handler/crash_report_upload_thread.h +++ b/handler/crash_report_upload_thread.h @@ -108,6 +108,9 @@ class CrashReportUploadThread : public WorkerThread::Delegate, //! It is expected to only be called from the same thread that called Start(). void Stop() override; + //! \return `true` if the thread is running, `false` if it is not. + bool is_running() const { return thread_.is_running(); } + private: //! \brief The result code from UploadReport(). enum class UploadResult { diff --git a/util/ios/ios_system_data_collector.h b/util/ios/ios_system_data_collector.h index 035f9d81e7..916a674560 100644 --- a/util/ios/ios_system_data_collector.h +++ b/util/ios/ios_system_data_collector.h @@ -17,6 +17,7 @@ #import +#include #include namespace crashpad { @@ -41,28 +42,25 @@ class IOSSystemDataCollector { int DaylightOffsetSeconds() const { return daylight_offset_seconds_; } const std::string& StandardName() const { return standard_name_; } const std::string& DaylightName() const { return daylight_name_; } + bool IsApplicationActive() const { return active_; } // Currently unused by minidump. int Orientation() const { return orientation_; } + // A completion callback that takes a bool indicating that the application has + // become active or inactive. + using ActiveApplicationCallback = std::function; + + void SetActiveApplicationCallback(ActiveApplicationCallback callback) { + active_application_callback_ = callback; + } + private: - // Notification handlers. + // Notification handlers for time zone, orientation and active state. void InstallHandlers(); - static void SystemTimeZoneDidChangeNotificationHandler( - CFNotificationCenterRef center, - void* observer, - CFStringRef name, - const void* object, - CFDictionaryRef userInfo); void SystemTimeZoneDidChangeNotification(); - - static void OrientationDidChangeNotificationHandler( - CFNotificationCenterRef center, - void* observer, - CFStringRef name, - const void* object, - CFDictionaryRef userInfo); void OrientationDidChangeNotification(); + void ApplicationDidChangeActiveNotification(); int major_version_; int minor_version_; @@ -72,6 +70,7 @@ class IOSSystemDataCollector { bool is_extension_; std::string machine_description_; int orientation_; + bool active_; int processor_count_; std::string cpu_vendor_; bool has_next_daylight_saving_time_; @@ -80,6 +79,7 @@ class IOSSystemDataCollector { int daylight_offset_seconds_; std::string standard_name_; std::string daylight_name_; + ActiveApplicationCallback active_application_callback_; }; } // namespace internal diff --git a/util/ios/ios_system_data_collector.mm b/util/ios/ios_system_data_collector.mm index 366be46481..6d39b6d2d4 100644 --- a/util/ios/ios_system_data_collector.mm +++ b/util/ios/ios_system_data_collector.mm @@ -49,6 +49,24 @@ return value; } +template +void AddObserver(CFStringRef notification_name, T* observer) { + CFNotificationCenterAddObserver( + CFNotificationCenterGetLocalCenter(), + observer, + [](CFNotificationCenterRef center, + void* observer_vp, + CFNotificationName name, + const void* object, + CFDictionaryRef userInfo) { + T* observer = reinterpret_cast(observer_vp); + (observer->*M)(); + }, + notification_name, + nullptr, + CFNotificationSuspensionBehaviorDeliverImmediately); +} + } // namespace namespace crashpad { @@ -131,35 +149,30 @@ void IOSSystemDataCollector::InstallHandlers() { // Timezone. - CFNotificationCenterAddObserver( - CFNotificationCenterGetLocalCenter(), - this, - IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler, - reinterpret_cast(NSSystemTimeZoneDidChangeNotification), - nullptr, - CFNotificationSuspensionBehaviorDeliverImmediately); + AddObserver( + (__bridge CFStringRef)NSSystemTimeZoneDidChangeNotification, this); SystemTimeZoneDidChangeNotification(); // Orientation. - CFNotificationCenterAddObserver( - CFNotificationCenterGetLocalCenter(), - this, - IOSSystemDataCollector::OrientationDidChangeNotificationHandler, - reinterpret_cast(UIDeviceOrientationDidChangeNotification), - nullptr, - CFNotificationSuspensionBehaviorDeliverImmediately); + AddObserver( + (__bridge CFStringRef)UIDeviceOrientationDidChangeNotification, this); OrientationDidChangeNotification(); -} -// static -void IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler( - CFNotificationCenterRef center, - void* observer, - CFStringRef name, - const void* object, - CFDictionaryRef userInfo) { - static_cast(observer) - ->SystemTimeZoneDidChangeNotification(); + // Foreground/Background. Extensions shouldn't use UIApplication*. + if (!is_extension_) { + AddObserver< + IOSSystemDataCollector, + &IOSSystemDataCollector::ApplicationDidChangeActiveNotification>( + (__bridge CFStringRef)UIApplicationDidBecomeActiveNotification, this); + AddObserver< + IOSSystemDataCollector, + &IOSSystemDataCollector::ApplicationDidChangeActiveNotification>( + (__bridge CFStringRef)UIApplicationDidEnterBackgroundNotification, + this); + ApplicationDidChangeActiveNotification(); + } } void IOSSystemDataCollector::SystemTimeZoneDidChangeNotification() { @@ -197,21 +210,20 @@ } } -// static -void IOSSystemDataCollector::OrientationDidChangeNotificationHandler( - CFNotificationCenterRef center, - void* observer, - CFStringRef name, - const void* object, - CFDictionaryRef userInfo) { - static_cast(observer) - ->OrientationDidChangeNotification(); -} - void IOSSystemDataCollector::OrientationDidChangeNotification() { orientation_ = base::saturated_cast([[UIDevice currentDevice] orientation]); } +void IOSSystemDataCollector::ApplicationDidChangeActiveNotification() { + dispatch_assert_queue_debug(dispatch_get_main_queue()); + bool old_active = active_; + active_ = [UIApplication sharedApplication].applicationState == + UIApplicationStateActive; + if (active_ != old_active && active_application_callback_) { + active_application_callback_(active_); + } +} + } // namespace internal } // namespace crashpad From 25e67e285c01b2b0c7d654dc2238176f0f1a56c3 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 23 Mar 2022 17:20:33 -0400 Subject: [PATCH 135/478] ios: Track last NSException in ObjcException preprocessor. Some sinkholes use objc_exception_throw instead of rethrow, which gives the preprocessor a second, incorrect, attempt to process the NSException. This also means if the processor misses the first sinkhole, on the second attempt the original throwing stack will be missing. Instead, track the original NSException and ignore any followup calls to the ObjcExceptionPreprocessor with the same NSException. Also creates a ExceptionPreprocessorState class to manage the complex types. This will be used in a followup CL to finalize caught NSExceptions using the uncaught handler. Bug: 1300171 Change-Id: I1f9f2c7ee79c7a16585103f04831217979e9332b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3530246 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/ios_handler/exception_processor.mm | 153 ++++++++++++++++------ 1 file changed, 111 insertions(+), 42 deletions(-) diff --git a/client/ios_handler/exception_processor.mm b/client/ios_handler/exception_processor.mm index 33981326f1..7b689c5433 100644 --- a/client/ios_handler/exception_processor.mm +++ b/client/ios_handler/exception_processor.mm @@ -53,6 +53,8 @@ #include "client/annotation.h" #include "client/simulate_crash_ios.h" +namespace crashpad { + namespace { // From 10.15.0 objc4-779.1/runtime/objc-exception.mm. @@ -132,16 +134,67 @@ int LoggingUnwStep(unw_cursor_t* cursor) { return FormatStackTrace(addresses, 1024); } -crashpad::ObjcExceptionDelegate* g_exception_delegate; -objc_exception_preprocessor g_next_preprocessor; -NSUncaughtExceptionHandler* g_next_uncaught_exception_handler; +//! \brief Helper class to own the complex types used by the Objective-C +//! exception preprocessor. +class ExceptionPreprocessorState { + public: + ExceptionPreprocessorState(const ExceptionPreprocessorState&) = delete; + ExceptionPreprocessorState& operator=(const ExceptionPreprocessorState&) = + delete; + + static ExceptionPreprocessorState* Get() { + static ExceptionPreprocessorState* instance = []() { + return new ExceptionPreprocessorState(); + }(); + return instance; + } + + // Inform the delegate of the uncaught exception and remove the global + // uncaught exception handler so we don't record this twice. + void HandleUncaughtException(NativeCPUContext* cpu_context) { + exception_delegate_->HandleUncaughtNSExceptionWithContext(cpu_context); + + NSSetUncaughtExceptionHandler(next_uncaught_exception_handler_); + next_uncaught_exception_handler_ = nullptr; + } + + id MaybeCallNextPreprocessor(id exception) { + return next_preprocessor_ ? next_preprocessor_(exception) : exception; + } + + // Register the objc_setExceptionPreprocessor and NSUncaughtExceptionHandler. + void Install(ObjcExceptionDelegate* delegate); + + // Restore the objc_setExceptionPreprocessor and NSUncaughtExceptionHandler. + void Uninstall(); + + NSException* last_exception() { return last_exception_; } + void set_last_exception(NSException* exception) { + [last_exception_ release]; + last_exception_ = [exception retain]; + } + + ObjcExceptionDelegate* exception_delegate() { return exception_delegate_; } + + private: + ExceptionPreprocessorState() = default; + ~ExceptionPreprocessorState() = default; + + // Recorded last NSException in case the exception is caught and thrown again + // (without using objc_exception_rethrow.) + NSException* last_exception_ = nil; + + ObjcExceptionDelegate* exception_delegate_ = nullptr; + objc_exception_preprocessor next_preprocessor_ = nullptr; + NSUncaughtExceptionHandler* next_uncaught_exception_handler_ = nullptr; +}; static void SetNSExceptionAnnotations(NSException* exception, std::string& name, std::string& reason) { @try { name = base::SysNSStringToUTF8(exception.name); - static crashpad::StringAnnotation<256> nameKey("exceptionName"); + static StringAnnotation<256> nameKey("exceptionName"); nameKey.Set(name); } @catch (id name_exception) { LOG(ERROR) << "Unable to read uncaught Objective-C exception name."; @@ -149,7 +202,7 @@ static void SetNSExceptionAnnotations(NSException* exception, @try { reason = base::SysNSStringToUTF8(exception.reason); - static crashpad::StringAnnotation<512> reasonKey("exceptionReason"); + static StringAnnotation<512> reasonKey("exceptionReason"); reasonKey.Set(reason); } @catch (id reason_exception) { LOG(ERROR) << "Unable to read uncaught Objective-C exception reason."; @@ -157,7 +210,7 @@ static void SetNSExceptionAnnotations(NSException* exception, @try { if (exception.userInfo) { - static crashpad::StringAnnotation<512> userInfoKey("exceptionUserInfo"); + static StringAnnotation<512> userInfoKey("exceptionUserInfo"); userInfoKey.Set(base::SysNSStringToUTF8( [NSString stringWithFormat:@"%@", exception.userInfo])); } @@ -170,21 +223,24 @@ static void ObjcUncaughtExceptionHandler(NSException* exception) { std::string name, reason; SetNSExceptionAnnotations(exception, name, reason); NSArray* addressArray = [exception callStackReturnAddresses]; + + ObjcExceptionDelegate* exception_delegate = + ExceptionPreprocessorState::Get()->exception_delegate(); if ([addressArray count] > 0) { - static crashpad::StringAnnotation<256> nameKey("UncaughtNSException"); + static StringAnnotation<256> nameKey("UncaughtNSException"); nameKey.Set("true"); std::vector addresses; for (NSNumber* address in addressArray) addresses.push_back([address unsignedLongLongValue]); - g_exception_delegate->HandleUncaughtNSException(&addresses[0], - addresses.size()); + exception_delegate->HandleUncaughtNSException(&addresses[0], + addresses.size()); } else { LOG(WARNING) << "Uncaught Objective-C exception name: " << name << " reason: " << reason << " with no " << " -callStackReturnAddresses."; - crashpad::NativeCPUContext cpu_context; - crashpad::CaptureContext(&cpu_context); - g_exception_delegate->HandleUncaughtNSExceptionWithContext(&cpu_context); + NativeCPUContext cpu_context; + CaptureContext(&cpu_context); + exception_delegate->HandleUncaughtNSExceptionWithContext(&cpu_context); } } @@ -197,15 +253,13 @@ static __attribute__((noinline)) id HANDLE_UNCAUGHT_NSEXCEPTION( SetNSExceptionAnnotations(exception, name, reason); LOG(WARNING) << "Handling Objective-C exception name: " << name << " reason: " << reason << " with sinkhole: " << sinkhole; - crashpad::NativeCPUContext cpu_context; - crashpad::CaptureContext(&cpu_context); - g_exception_delegate->HandleUncaughtNSExceptionWithContext(&cpu_context); - - // Remove the uncaught exception handler so we don't record this twice. - NSSetUncaughtExceptionHandler(g_next_uncaught_exception_handler); - g_next_uncaught_exception_handler = nullptr; + NativeCPUContext cpu_context; + CaptureContext(&cpu_context); - return g_next_preprocessor ? g_next_preprocessor(exception) : exception; + ExceptionPreprocessorState* preprocessor_state = + ExceptionPreprocessorState::Get(); + preprocessor_state->HandleUncaughtException(&cpu_context); + return preprocessor_state->MaybeCallNextPreprocessor(exception); } // Returns true if |path| equals |sinkhole| on device. Simulator paths prepend @@ -226,13 +280,23 @@ bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) { } id ObjcExceptionPreprocessor(id exception) { + // Some sinkholes don't use objc_exception_rethrow when they should, which + // would otherwise prevent the exception_preprocessor from getting called + // again. Because of this, track the most recently seen exception and + // ignore it. + ExceptionPreprocessorState* preprocessor_state = + ExceptionPreprocessorState::Get(); + if ([preprocessor_state->last_exception() isEqual:exception]) { + return preprocessor_state->MaybeCallNextPreprocessor(exception); + } + preprocessor_state->set_last_exception(exception); + static bool seen_first_exception; - static crashpad::StringAnnotation<256> firstexception("firstexception"); - static crashpad::StringAnnotation<256> lastexception("lastexception"); - static crashpad::StringAnnotation<1024> firstexception_bt( - "firstexception_bt"); - static crashpad::StringAnnotation<1024> lastexception_bt("lastexception_bt"); + static StringAnnotation<256> firstexception("firstexception"); + static StringAnnotation<256> lastexception("lastexception"); + static StringAnnotation<1024> firstexception_bt("firstexception_bt"); + static StringAnnotation<1024> lastexception_bt("lastexception_bt"); auto* key = seen_first_exception ? &lastexception : &firstexception; auto* bt_key = seen_first_exception ? &lastexception_bt : &firstexception_bt; NSString* value = [NSString @@ -470,36 +534,41 @@ id ObjcExceptionPreprocessor(id exception) { } // Forward to the next preprocessor. - return g_next_preprocessor ? g_next_preprocessor(exception) : exception; + return preprocessor_state->MaybeCallNextPreprocessor(exception); } -} // namespace - -namespace crashpad { - -void InstallObjcExceptionPreprocessor(ObjcExceptionDelegate* delegate) { - DCHECK(!g_next_preprocessor); +void ExceptionPreprocessorState::Install(ObjcExceptionDelegate* delegate) { + DCHECK(!next_preprocessor_); + exception_delegate_ = delegate; // Preprocessor. - g_next_preprocessor = + next_preprocessor_ = objc_setExceptionPreprocessor(&ObjcExceptionPreprocessor); // Uncaught processor. - g_exception_delegate = delegate; - g_next_uncaught_exception_handler = NSGetUncaughtExceptionHandler(); + next_uncaught_exception_handler_ = NSGetUncaughtExceptionHandler(); NSSetUncaughtExceptionHandler(&ObjcUncaughtExceptionHandler); } -void UninstallObjcExceptionPreprocessor() { - DCHECK(g_next_preprocessor); +void ExceptionPreprocessorState::Uninstall() { + DCHECK(next_preprocessor_); + objc_setExceptionPreprocessor(next_preprocessor_); + next_preprocessor_ = nullptr; + + NSSetUncaughtExceptionHandler(next_uncaught_exception_handler_); + next_uncaught_exception_handler_ = nullptr; + + exception_delegate_ = nullptr; +} - objc_setExceptionPreprocessor(g_next_preprocessor); - g_exception_delegate = nullptr; +} // namespace - NSSetUncaughtExceptionHandler(g_next_uncaught_exception_handler); - g_next_uncaught_exception_handler = nullptr; +void InstallObjcExceptionPreprocessor(ObjcExceptionDelegate* delegate) { + ExceptionPreprocessorState::Get()->Install(delegate); +} - g_next_preprocessor = nullptr; +void UninstallObjcExceptionPreprocessor() { + ExceptionPreprocessorState::Get()->Uninstall(); } } // namespace crashpad From f88a116c0e2e6f38c348a889fb28921510955802 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 23 Mar 2022 20:43:12 -0400 Subject: [PATCH 136/478] Update Crashpad scripts to python3 Also update mini_chromium to f87a38442a9e for python3 changes. Change-Id: I4ca7aa4cc9dcc97698fc0bc13cfb339421668074 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3542572 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- .gn | 1 + DEPS | 4 ++-- build/ios/convert_gn_xcodeproj.py | 2 +- build/ios/setup_ios_gn.py | 21 ++++++--------------- doc/support/generate_doxygen.py | 2 +- snapshot/win/end_to_end_test.py | 2 +- util/mach/mig.py | 2 +- util/mach/mig_fix.py | 3 +-- util/mach/mig_gen.py | 2 +- 9 files changed, 15 insertions(+), 24 deletions(-) diff --git a/.gn b/.gn index d447a5537c..e4dc49c31f 100644 --- a/.gn +++ b/.gn @@ -13,3 +13,4 @@ # limitations under the License. buildconfig = "//build/BUILDCONFIG.gn" +script_executable = "python3" diff --git a/DEPS b/DEPS index 27e9520b46..5dd3d46fd3 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '6e2f204b4ae135c40a6c4b3c3a01f48a86c5e886', + 'f87a38442a9e7ba88d1c4f479e9167927eae84ed', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', @@ -169,7 +169,7 @@ hooks = [ 'pattern': '.', 'condition': 'run_setup_ios_gn and checkout_ios', 'action': [ - 'python', + 'python3', 'crashpad/build/ios/setup_ios_gn.py' ], }, diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py index d546279ce0..48c1752506 100755 --- a/build/ios/convert_gn_xcodeproj.py +++ b/build/ios/convert_gn_xcodeproj.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2020 The Crashpad Authors. All rights reserved. # diff --git a/build/ios/setup_ios_gn.py b/build/ios/setup_ios_gn.py index 9522ce6757..76e6381176 100755 --- a/build/ios/setup_ios_gn.py +++ b/build/ios/setup_ios_gn.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2020 The Crashpad Authors. All rights reserved. # @@ -23,29 +23,20 @@ import subprocess import sys import tempfile - -try: - import configparser -except ImportError: - import ConfigParser as configparser - -try: - import StringIO as io -except ImportError: - import io +import configparser +import io SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator') SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage') -class ConfigParserWithStringInterpolation(configparser.SafeConfigParser): +class ConfigParserWithStringInterpolation(configparser.ConfigParser): '''A .ini file parser that supports strings and environment variables.''' ENV_VAR_PATTERN = re.compile(r'\$([A-Za-z0-9_]+)') def values(self, section): - return map(lambda kv: self._UnquoteString(self._ExpandEnvVar(kv[1])), - configparser.ConfigParser.items(self, section)) + return [self._UnquoteString(self._ExpandEnvVar(kv[1])) for kv in configparser.ConfigParser.items(self, section)] def getstring(self, section, option): return self._UnquoteString(self._ExpandEnvVar(self.get(section, @@ -110,7 +101,7 @@ def _GetGnArgs(self): args.append(('target_cpu', target_cpu)) args.append( ('additional_target_cpus', - [cpu for cpu in cpu_values.itervalues() if cpu != target_cpu])) + [cpu for cpu in cpu_values.values() if cpu != target_cpu])) else: args.append(('target_cpu', cpu_values[build_arch])) diff --git a/doc/support/generate_doxygen.py b/doc/support/generate_doxygen.py index 577b51e596..7b28aa93d9 100755 --- a/doc/support/generate_doxygen.py +++ b/doc/support/generate_doxygen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2017 The Crashpad Authors. All rights reserved. # diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py index b1919adef4..aa606f981c 100755 --- a/snapshot/win/end_to_end_test.py +++ b/snapshot/win/end_to_end_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2015 The Crashpad Authors. All rights reserved. # diff --git a/util/mach/mig.py b/util/mach/mig.py index 53a7a5bd1d..c7a1543520 100755 --- a/util/mach/mig.py +++ b/util/mach/mig.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2019 The Crashpad Authors. All rights reserved. # diff --git a/util/mach/mig_fix.py b/util/mach/mig_fix.py index 6e2877136a..974c58df79 100755 --- a/util/mach/mig_fix.py +++ b/util/mach/mig_fix.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# coding: utf-8 +#!/usr/bin/env python3 # Copyright 2019 The Crashpad Authors. All rights reserved. # diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py index 99b4f7ec6b..c29d0d149a 100755 --- a/util/mach/mig_gen.py +++ b/util/mach/mig_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2019 The Crashpad Authors. All rights reserved. # From dedbc0f61b5feec0857e7abbdc4979f68abbb33d Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 25 Mar 2022 10:36:27 -0400 Subject: [PATCH 137/478] Update Crashpad bot scripts to python3. Change-Id: Ie3848c2f2bbbe34ca3a5e7da5e7d05e3cfba5b72 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3549021 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- .vpython3 | 32 ++++++++++++++++++++++++++++++++ build/run_tests.py | 31 ++++++++++++++++--------------- snapshot/win/end_to_end_test.py | 18 +++++++++++++----- 3 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 .vpython3 diff --git a/.vpython3 b/.vpython3 new file mode 100644 index 0000000000..0d7baf9efc --- /dev/null +++ b/.vpython3 @@ -0,0 +1,32 @@ +# Copyright 2022 The Crashpad Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This is a vpython "spec" file. +# +# It describes patterns for python wheel dependencies of the python scripts. +# +# Read more about `vpython` and how to modify this file here: +# https://chromium.googlesource.com/infra/infra/+/master/doc/users/vpython.md + +# This is needed for snapshot/win/end_to_end_test.py. +wheel: < + name: "infra/python/wheels/pywin32/${vpython_platform}" + version: "version:300" + match_tag: < + platform: "win32" + > + match_tag: < + platform: "win_amd64" + > +> diff --git a/build/run_tests.py b/build/run_tests.py index f48652ff78..71d1d9c34d 100755 --- a/build/run_tests.py +++ b/build/run_tests.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# coding: utf-8 +#!/usr/bin/env python3 # Copyright 2014 The Crashpad Authors. All rights reserved. # @@ -15,8 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function - import argparse import os import pipes @@ -40,7 +37,7 @@ def _FindGNFromBinaryDir(binary_dir): build_ninja = os.path.join(binary_dir, 'build.ninja') if os.path.isfile(build_ninja): - with open(build_ninja, 'rb') as f: + with open(build_ninja, 'r') as f: # Look for the always-generated regeneration rule of the form: # # rule gn @@ -78,10 +75,11 @@ def _BinaryDirTargetOS(binary_dir): ], shell=IS_WINDOWS_HOST, stdout=subprocess.PIPE, - stderr=open(os.devnull)) + stderr=open(os.devnull), + text=True) value = popen.communicate()[0] if popen.returncode == 0: - match = re.match('target_os = "(.*)"$', value.decode('utf-8')) + match = re.match('target_os = "(.*)"$', value) if match: return match.group(1) @@ -196,13 +194,14 @@ def _adb_shell(command_args, env={}): child = subprocess.Popen(adb_command, shell=IS_WINDOWS_HOST, stdin=open(os.devnull), - stdout=subprocess.PIPE) + stdout=subprocess.PIPE, + text=True) FINAL_LINE_RE = re.compile('status=(\d+)$') final_line = None while True: # Use readline so that the test output appears “live” when running. - data = child.stdout.readline().decode('utf-8') + data = child.stdout.readline() if data == '': break if final_line is not None: @@ -369,10 +368,11 @@ def xcuitest(binary_dir, test): xctestrun_path = f.name print(xctestrun_path) - if is_xcuitest: - plistlib.writePlist(xcuitest(binary_dir, test), xctestrun_path) - else: - plistlib.writePlist(xctest(binary_dir, test), xctestrun_path) + with open(xctestrun_path, 'wb') as fp: + if is_xcuitest: + plistlib.dump(xcuitest(binary_dir, test), fp) + else: + plistlib.dump(xctest(binary_dir, test), fp) subprocess.check_call([ 'xcodebuild', 'test-without-building', '-xctestrun', xctestrun_path, @@ -421,10 +421,11 @@ def main(args): android_device = os.environ.get('ANDROID_DEVICE') if not android_device: adb_devices = subprocess.check_output(['adb', 'devices'], - shell=IS_WINDOWS_HOST) + shell=IS_WINDOWS_HOST, + text=True) devices = [] for line in adb_devices.splitlines(): - line = line.decode('utf-8') + line = line if (line == 'List of devices attached' or re.match('^\* daemon .+ \*$', line) or line == ''): continue diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py index aa606f981c..9d319078d8 100755 --- a/snapshot/win/end_to_end_test.py +++ b/snapshot/win/end_to_end_test.py @@ -14,13 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function - import os import platform import pywintypes import random import re +import struct import subprocess import sys import tempfile @@ -104,7 +103,7 @@ def NamedPipeExistsAndReady(pipe_name): try: win32pipe.WaitNamedPipe(pipe_name, win32pipe.NMPWAIT_WAIT_FOREVER) except pywintypes.error as e: - if e[0] == winerror.ERROR_FILE_NOT_FOUND: + if e.winerror == winerror.ERROR_FILE_NOT_FOUND: return False raise return True @@ -152,6 +151,14 @@ def GetDumpFromProgram(out_dir, pipe_name, executable_name, expect_exit_code, ] + list(args)) print('Running %s' % os.path.basename(command[0])) exit_code = subprocess.call(command) + + # Some win32con codes are negative signed integers, whereas all exit + # codes are unsigned integers. Convert from signed to unsigned. + if expect_exit_code < 0: + expect_exit_code = struct.unpack('I', + struct.pack('i', + expect_exit_code))[0] + if exit_code != expect_exit_code: raise subprocess.CalledProcessError(exit_code, executable_name) @@ -160,7 +167,8 @@ def GetDumpFromProgram(out_dir, pipe_name, executable_name, expect_exit_code, '--database=' + test_database, '--show-pending-reports', '--show-all-report-info', - ]) + ], + text=True) for line in out.splitlines(): if line.strip().startswith('Path:'): return line.partition(':')[2].strip() @@ -205,7 +213,7 @@ def __init__(self, cdb_path, dump_path, command): # Run a command line that loads the dump, runs the specified cdb # command, and then quits, and capturing stdout. self.out = subprocess.check_output( - [cdb_path, '-z', dump_path, '-c', command + ';q']) + [cdb_path, '-z', dump_path, '-c', command + ';q'], text=True) def Check(self, pattern, message, re_flags=0): match_obj = re.search(pattern, self.out, re_flags) From 8c7caef421e070c806aa878be2a439a5e1ddbdfd Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 24 Mar 2022 19:43:01 -0400 Subject: [PATCH 138/478] ios: Don't report preprocessed NSExceptions until the uncaught handler. Change the ObjExceptionProcessor to write intermediate dumps to a temporary location until they are confirmed by the UncaughtExceptionHandler. Because the exception preprocessor uses heuristics to detect iOS sinkholes, it's possible for an exception to be identified as fatal, but not actual trigger the uncaught exception handler. If the processor detects more than one fatal exception, it will unregister itself and indicate this in the second dump with the key 'MultipleHandledUncaughtNSException'. This changes also consolidates and simplifies some methods in the InProcessHandler. Change-Id: Ifc457e974d25f533b77cfd18b702129fdfb10a75 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3529968 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/crashpad_client_ios.cc | 31 +++- client/ios_handler/exception_processor.h | 23 +++ client/ios_handler/exception_processor.mm | 164 ++++++++++++------- client/ios_handler/in_process_handler.cc | 43 ++--- client/ios_handler/in_process_handler.h | 19 ++- test/ios/crash_type_xctest.mm | 16 ++ test/ios/host/cptest_application_delegate.mm | 23 +++ test/ios/host/cptest_shared_object.h | 3 + 8 files changed, 214 insertions(+), 108 deletions(-) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index af9524ef35..2a737f3ccb 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -128,8 +128,8 @@ class CrashHandler : public Thread, void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); base::FilePath path; - if (!in_process_handler_.DumpExceptionFromSimulatedMachException(context, - &path)) { + if (!in_process_handler_.DumpExceptionFromSimulatedMachException( + context, kMachExceptionSimulated, &path)) { return; } @@ -140,8 +140,8 @@ class CrashHandler : public Thread, void DumpWithoutCrashAtPath(NativeCPUContext* context, const base::FilePath& path) { - in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(context, - path); + in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath( + context, kMachExceptionSimulated, path); } void StartProcessingPendingReports() { @@ -323,7 +323,9 @@ class CrashHandler : public Thread, void HandleUncaughtNSExceptionWithContext( NativeCPUContext* context) override { - in_process_handler_.DumpExceptionFromNSExceptionWithContext(context); + base::FilePath path; + in_process_handler_.DumpExceptionFromSimulatedMachException( + context, kMachExceptionFromNSException, &path); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -331,6 +333,25 @@ class CrashHandler : public Thread, CHECK(Signals::InstallDefaultHandler(SIGABRT)); } + void HandleUncaughtNSExceptionWithContextAtPath( + NativeCPUContext* context, + const base::FilePath& path) override { + in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath( + context, kMachExceptionFromNSException, path); + } + + bool MoveIntermediateDumpAtPathToPending( + const base::FilePath& path) override { + if (in_process_handler_.MoveIntermediateDumpAtPathToPending(path)) { + // After uncaught exceptions are reported, the system immediately triggers + // a call to std::terminate()/abort(). Remove the abort handler so a + // second dump isn't generated. + CHECK(Signals::InstallDefaultHandler(SIGABRT)); + return true; + } + return false; + } + // The signal handler installed at OS-level. static void CatchAndReraiseSignal(int signo, siginfo_t* siginfo, diff --git a/client/ios_handler/exception_processor.h b/client/ios_handler/exception_processor.h index 9be63134da..233f7e45af 100644 --- a/client/ios_handler/exception_processor.h +++ b/client/ios_handler/exception_processor.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ #define CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ +#include "base/files/file_path.h" #include "util/misc/capture_context.h" namespace crashpad { @@ -38,6 +39,28 @@ class ObjcExceptionDelegate { virtual void HandleUncaughtNSException(const uint64_t* frames, const size_t num_frames) = 0; + //! \brief Generate an intermediate dump from an NSException caught with its + //! associated CPU context. Because the method for intercepting + //! exceptions is imperfect, write the the intermediate dump to a + //! temporary location specified by \a path. If the NSException matches + //! the one used in the UncaughtExceptionHandler, call + //! MoveIntermediateDumpAtPathToPending to move to the proper Crashpad + //! database pending location. + //! + //! \param[in] context The cpu context of the thread throwing an exception. + //! \param[in] path Path to write the intermediate dump. + virtual void HandleUncaughtNSExceptionWithContextAtPath( + NativeCPUContext* context, + const base::FilePath& path) = 0; + + //! \brief Moves an intermediate dump to the pending directory. This is meant + //! to be used by the UncaughtExceptionHandler, when the NSException + //! caught by the preprocessor matches the UncaughtExceptionHandler. + //! + //! \param[in] path Path to the specific intermediate dump. + virtual bool MoveIntermediateDumpAtPathToPending( + const base::FilePath& path) = 0; + protected: ~ObjcExceptionDelegate() {} }; diff --git a/client/ios_handler/exception_processor.mm b/client/ios_handler/exception_processor.mm index 7b689c5433..3211228c22 100644 --- a/client/ios_handler/exception_processor.mm +++ b/client/ios_handler/exception_processor.mm @@ -134,6 +134,36 @@ int LoggingUnwStep(unw_cursor_t* cursor) { return FormatStackTrace(addresses, 1024); } +static void SetNSExceptionAnnotations(NSException* exception, + std::string& name, + std::string& reason) { + @try { + name = base::SysNSStringToUTF8(exception.name); + static StringAnnotation<256> nameKey("exceptionName"); + nameKey.Set(name); + } @catch (id name_exception) { + LOG(ERROR) << "Unable to read uncaught Objective-C exception name."; + } + + @try { + reason = base::SysNSStringToUTF8(exception.reason); + static StringAnnotation<512> reasonKey("exceptionReason"); + reasonKey.Set(reason); + } @catch (id reason_exception) { + LOG(ERROR) << "Unable to read uncaught Objective-C exception reason."; + } + + @try { + if (exception.userInfo) { + static StringAnnotation<512> userInfoKey("exceptionUserInfo"); + userInfoKey.Set(base::SysNSStringToUTF8( + [NSString stringWithFormat:@"%@", exception.userInfo])); + } + } @catch (id user_info_exception) { + LOG(ERROR) << "Unable to read uncaught Objective-C exception user info."; + } +} + //! \brief Helper class to own the complex types used by the Objective-C //! exception preprocessor. class ExceptionPreprocessorState { @@ -149,13 +179,73 @@ int LoggingUnwStep(unw_cursor_t* cursor) { return instance; } - // Inform the delegate of the uncaught exception and remove the global - // uncaught exception handler so we don't record this twice. - void HandleUncaughtException(NativeCPUContext* cpu_context) { - exception_delegate_->HandleUncaughtNSExceptionWithContext(cpu_context); + // Writes an intermediate dumps to a temporary location to be used by the + // final UncaughtExceptionHandler and notifies the preprocessor chain. + id HandleUncaughtException(NativeCPUContext* cpu_context, id exception) { + // If this isn't the first time the preprocessor has detected an uncaught + // NSException, note this in the second intermediate dump. + objc_exception_preprocessor next_preprocessor = next_preprocessor_; + static bool handled_first_exception; + if (handled_first_exception) { + static StringAnnotation<5> name_key("MultipleHandledUncaughtNSException"); + name_key.Set("true"); + + // Unregister so we stop getting in the way of the exception processor if + // we aren't correctly identifying sinkholes. The final uncaught exception + // handler is still active. + objc_setExceptionPreprocessor(next_preprocessor_); + next_preprocessor_ = nullptr; + } + handled_first_exception = true; + + // Use tmp/ for this intermediate dump path. Normally these dumps are + // written to the "pending-serialized-ios-dump" folder and are eligable for + // the next pass to convert pending intermediate dumps to minidump files. + // Since this intermediate dump isn't eligable until the uncaught handler, + // use tmp/. + base::FilePath path(base::SysNSStringToUTF8([NSTemporaryDirectory() + stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]])); + exception_delegate_->HandleUncaughtNSExceptionWithContextAtPath(cpu_context, + path); + last_handled_intermediate_dump_ = path; + + return next_preprocessor ? next_preprocessor(exception) : exception; + } - NSSetUncaughtExceptionHandler(next_uncaught_exception_handler_); - next_uncaught_exception_handler_ = nullptr; + // If the PreprocessException already captured this exception via + // HANDLE_UNCAUGHT_NSEXCEPTION. Move last_handled_intermediate_dump_ to + // the pending intermediate dump directory and return true. Otherwise the + // preprocessor didn't catch anything, so pass the frames or just the context + // to the exception_delegate. + void FinalizeUncaughtNSException(id exception) { + if ([last_exception_ isEqual:exception] && + !last_handled_intermediate_dump_.empty() && + exception_delegate_->MoveIntermediateDumpAtPathToPending( + last_handled_intermediate_dump_)) { + last_handled_intermediate_dump_ = base::FilePath(); + return; + } + + std::string name, reason; + SetNSExceptionAnnotations(exception, name, reason); + NSArray* address_array = [exception callStackReturnAddresses]; + + if ([address_array count] > 0) { + static StringAnnotation<256> name_key("UncaughtNSException"); + name_key.Set("true"); + std::vector addresses; + for (NSNumber* address in address_array) + addresses.push_back([address unsignedLongLongValue]); + exception_delegate_->HandleUncaughtNSException(&addresses[0], + addresses.size()); + } else { + LOG(WARNING) << "Uncaught Objective-C exception name: " << name + << " reason: " << reason << " with no " + << " -callStackReturnAddresses."; + NativeCPUContext cpu_context; + CaptureContext(&cpu_context); + exception_delegate_->HandleUncaughtNSExceptionWithContext(&cpu_context); + } } id MaybeCallNextPreprocessor(id exception) { @@ -174,12 +264,14 @@ void set_last_exception(NSException* exception) { last_exception_ = [exception retain]; } - ObjcExceptionDelegate* exception_delegate() { return exception_delegate_; } - private: ExceptionPreprocessorState() = default; ~ExceptionPreprocessorState() = default; + // Location of the intermediate dump generated after an exception triggered + // HANDLE_UNCAUGHT_NSEXCEPTION. + base::FilePath last_handled_intermediate_dump_; + // Recorded last NSException in case the exception is caught and thrown again // (without using objc_exception_rethrow.) NSException* last_exception_ = nil; @@ -189,59 +281,8 @@ void set_last_exception(NSException* exception) { NSUncaughtExceptionHandler* next_uncaught_exception_handler_ = nullptr; }; -static void SetNSExceptionAnnotations(NSException* exception, - std::string& name, - std::string& reason) { - @try { - name = base::SysNSStringToUTF8(exception.name); - static StringAnnotation<256> nameKey("exceptionName"); - nameKey.Set(name); - } @catch (id name_exception) { - LOG(ERROR) << "Unable to read uncaught Objective-C exception name."; - } - - @try { - reason = base::SysNSStringToUTF8(exception.reason); - static StringAnnotation<512> reasonKey("exceptionReason"); - reasonKey.Set(reason); - } @catch (id reason_exception) { - LOG(ERROR) << "Unable to read uncaught Objective-C exception reason."; - } - - @try { - if (exception.userInfo) { - static StringAnnotation<512> userInfoKey("exceptionUserInfo"); - userInfoKey.Set(base::SysNSStringToUTF8( - [NSString stringWithFormat:@"%@", exception.userInfo])); - } - } @catch (id user_info_exception) { - LOG(ERROR) << "Unable to read uncaught Objective-C exception user info."; - } -} - static void ObjcUncaughtExceptionHandler(NSException* exception) { - std::string name, reason; - SetNSExceptionAnnotations(exception, name, reason); - NSArray* addressArray = [exception callStackReturnAddresses]; - - ObjcExceptionDelegate* exception_delegate = - ExceptionPreprocessorState::Get()->exception_delegate(); - if ([addressArray count] > 0) { - static StringAnnotation<256> nameKey("UncaughtNSException"); - nameKey.Set("true"); - std::vector addresses; - for (NSNumber* address in addressArray) - addresses.push_back([address unsignedLongLongValue]); - exception_delegate->HandleUncaughtNSException(&addresses[0], - addresses.size()); - } else { - LOG(WARNING) << "Uncaught Objective-C exception name: " << name - << " reason: " << reason << " with no " - << " -callStackReturnAddresses."; - NativeCPUContext cpu_context; - CaptureContext(&cpu_context); - exception_delegate->HandleUncaughtNSExceptionWithContext(&cpu_context); - } + ExceptionPreprocessorState::Get()->FinalizeUncaughtNSException(exception); } // This function is used to make it clear to the crash processor that an @@ -258,8 +299,7 @@ static __attribute__((noinline)) id HANDLE_UNCAUGHT_NSEXCEPTION( ExceptionPreprocessorState* preprocessor_state = ExceptionPreprocessorState::Get(); - preprocessor_state->HandleUncaughtException(&cpu_context); - return preprocessor_state->MaybeCallNextPreprocessor(exception); + return preprocessor_state->HandleUncaughtException(&cpu_context, exception); } // Returns true if |path| equals |sinkhole| on device. Simulator paths prepend diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index 0642884d08..abde07f609 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -179,37 +179,6 @@ void InProcessHandler::DumpExceptionFromMachException( old_state_count); } -void InProcessHandler::DumpExceptionFromNSExceptionWithContext( - NativeCPUContext* context) { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - // This does not use the cached writer. NSExceptionWithContext comes from - // the objective-c preprocessor and uses a best-guess approach to detecting - // uncaught exceptions, and may be called multiple times. - base::FilePath writer_path = NewLockedFilePath(); - base::FilePath writer_path_unlocked = writer_path.RemoveFinalExtension(); - std::unique_ptr unsafe_writer = - CreateWriterWithPath(writer_path); - ScopedLockedWriter writer(unsafe_writer.get(), - writer_path.value().c_str(), - writer_path_unlocked.value().c_str()); - if (!writer.GetWriter()) { - CRASHPAD_RAW_LOG("Cannot DumpExceptionFromNSException without writer"); - return; - } - - ScopedReport report(writer.GetWriter(), system_data_, annotations_); - InProcessIntermediateDumpHandler::WriteExceptionFromMachException( - writer.GetWriter(), - MACH_EXCEPTION_CODES, - mach_thread_self(), - kMachExceptionFromNSException, - kEmulatedMachExceptionCodes, - std::size(kEmulatedMachExceptionCodes), - MACHINE_THREAD_STATE, - reinterpret_cast(context), - MACHINE_THREAD_STATE_COUNT); -} - void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( const uint64_t* frames, const size_t num_frames) { @@ -230,14 +199,17 @@ void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( bool InProcessHandler::DumpExceptionFromSimulatedMachException( const NativeCPUContext* context, + exception_type_t exception, base::FilePath* path) { base::FilePath locked_path = NewLockedFilePath(); *path = locked_path.RemoveFinalExtension(); - return DumpExceptionFromSimulatedMachExceptionAtPath(context, locked_path); + return DumpExceptionFromSimulatedMachExceptionAtPath( + context, exception, locked_path); } bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( const NativeCPUContext* context, + exception_type_t exception, const base::FilePath& path) { // This does not use the cached writer. It's expected that simulated // exceptions can be called multiple times and there is no expectation that @@ -259,7 +231,7 @@ bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( writer.GetWriter(), MACH_EXCEPTION_CODES, mach_thread_self(), - kMachExceptionSimulated, + exception, kEmulatedMachExceptionCodes, std::size(kEmulatedMachExceptionCodes), MACHINE_THREAD_STATE, @@ -268,6 +240,11 @@ bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( return true; } +bool InProcessHandler::MoveIntermediateDumpAtPathToPending( + const base::FilePath& path) { + base::FilePath new_path_unlocked = NewLockedFilePath().RemoveFinalExtension(); + return MoveFileOrDirectory(path, new_path_unlocked); +} void InProcessHandler::ProcessIntermediateDumps( const std::map& annotations) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); diff --git a/client/ios_handler/in_process_handler.h b/client/ios_handler/in_process_handler.h index f551b90d9d..0e6b70b3c1 100644 --- a/client/ios_handler/in_process_handler.h +++ b/client/ios_handler/in_process_handler.h @@ -89,14 +89,6 @@ class InProcessHandler { ConstThreadState old_state, mach_msg_type_number_t old_state_count); - //! \brief Generate an intermediate dump from a NSException caught with its - //! associated CPU context. Because the method for intercepting - //! exceptions is imperfect, uses a new writer for the intermediate dump, - //! as it is possible for further exceptions to happen. - //! - //! \param[in] context - void DumpExceptionFromNSExceptionWithContext(NativeCPUContext* context); - //! \brief Generate an intermediate dump from an uncaught NSException. //! //! When the ObjcExceptionPreprocessor does not detect an NSException as it is @@ -118,9 +110,11 @@ class InProcessHandler { //! //! \param[in] context A pointer to a NativeCPUContext object for this //! simulated exception. + //! \param[in] exception //! \param[out] path The path of the intermediate dump generated. //! \return `true` if the pending intermediate dump could be written. bool DumpExceptionFromSimulatedMachException(const NativeCPUContext* context, + exception_type_t exception, base::FilePath* path); //! \brief Generate a simulated intermediate dump similar to a Mach exception @@ -128,12 +122,21 @@ class InProcessHandler { //! //! \param[in] context A pointer to a NativeCPUContext object for this //! simulated exception. + //! \param[in] exception //! \param[in] path Path to where the intermediate dump should be written. //! \return `true` if the pending intermediate dump could be written. bool DumpExceptionFromSimulatedMachExceptionAtPath( const NativeCPUContext* context, + exception_type_t exception, const base::FilePath& path); + //! \brief Moves an intermediate dump to the pending directory. This is meant + //! to be used by the UncaughtExceptionHandler, when NSException caught + //! by the preprocessor matches the UncaughtExceptionHandler. + //! + //! \param[in] path Path to the specific intermediate dump. + bool MoveIntermediateDumpAtPathToPending(const base::FilePath& path); + //! \brief Requests that the handler convert all intermediate dumps into //! minidumps and trigger an upload if possible. //! diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 9f41c5eaf9..27b4e1f7fe 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -166,6 +166,22 @@ - (void)testNSException { isEqualToString:@"NSInternalInconsistencyException"]); } +- (void)testUnhandledNSException { + [rootObject_ crashUnhandledNSException]; + [self verifyCrashReportException:crashpad::kMachExceptionFromNSException]; + NSDictionary* dict = [rootObject_ getAnnotations]; + NSString* uncaught_flag = + [dict[@"objects"][0] valueForKeyPath:@"UncaughtNSException"]; + XCTAssertTrue([uncaught_flag containsString:@"true"]); + NSString* userInfo = + [dict[@"objects"][1] valueForKeyPath:@"exceptionUserInfo"]; + XCTAssertTrue([userInfo containsString:@"Error Object= #include #include +#include #include #include #include #include #include +#include #include #import "Service/Sources/EDOHostNamingService.h" @@ -311,6 +313,27 @@ - (void)crashNSException { }); } +- (void)crashUnhandledNSException { + std::thread t([self]() { + @autoreleasepool { + @try { + NSError* error = [NSError errorWithDomain:@"com.crashpad.xcuitests" + code:200 + userInfo:@{@"Error Object" : self}]; + + [[NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Intentionally throwing error." + userInfo:@{NSUnderlyingErrorKey : error}] raise]; + } @catch (id reason_exception) { + // Intentionally use throw here to intentionally make a sinkhole that + // will be missed by ObjcPreprocessor. + objc_exception_throw(reason_exception); + } + } + }); + t.join(); +} + - (void)crashUnrecognizedSelectorAfterDelay { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index a43e5445e2..47ee7ad35d 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -73,6 +73,9 @@ // Trigger a crash with an uncaught NSException. - (void)crashNSException; +// Trigger a crash with an uncaught and unhandled NSException. +- (void)crashUnhandledNSException; + // Trigger an unrecognized selector after delay. - (void)crashUnrecognizedSelectorAfterDelay; From 4ead15ad8640ac75f24add06ddffd1f5c4983ab7 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 24 Mar 2022 22:20:35 -0400 Subject: [PATCH 139/478] ios: Fix googletest compile with latest Xcode. Ignore gmock-matchers_test.cc deprecated std::iterator. Change-Id: I008d7fc8bde34653d6bde8046875edfc5660f606 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3550545 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- third_party/googletest/BUILD.gn | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/third_party/googletest/BUILD.gn b/third_party/googletest/BUILD.gn index de1c84d444..6d98a38ba0 100644 --- a/third_party/googletest/BUILD.gn +++ b/third_party/googletest/BUILD.gn @@ -325,8 +325,10 @@ if (crashpad_is_in_chromium) { "-Wno-inconsistent-missing-override", # For googletest/googlemock/test/gmock-matchers_test.cc’s - # testing::googlemock_matchers_test::Unprintable::c_. + # testing::googlemock_matchers_test::Unprintable::c_ and deprecated + # std::iterator. "-Wno-unused-private-field", + "-Wno-deprecated-declarations", ] } From facfdb9e531d2987070fa75130f36bec9aaa54af Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 25 Mar 2022 08:36:39 -0400 Subject: [PATCH 140/478] Roll crashpad/third_party/edo/edo/ 6ffbf8331..727e55670 (28 commits) https://chromium.googlesource.com/external/github.com/google/eDistantObject.git/+log/6ffbf833173f..727e55670527 $ git log 6ffbf8331..727e55670 --date=short --no-merges --format='%ad %ae %s' 2022-03-24 strangewiz Fix up EDO with -Wunused-but-set-variable warning turned on. (#244) 2022-03-14 ynzhang Internal test update only. 2022-03-14 ynzhang Test update only. 2022-02-03 albertbow eDO won't block the object encoding if the object is passed by value. 2021-11-12 albertbow Change EDOHostService.keepDeviceConnection to readwrite and atomic. 2021-11-10 albertbow Change internal-only property from "readwrite/atomic" to "readonly/nonatomic". 2021-11-09 no-reply Add appropriate nonatomics to properties so we can enable `-Wimplicit-atomic-properties` 2021-11-07 no-reply Fix up EDO with `-Wbad-function-cast` warning turned on. 2021-11-07 no-reply Fix up EDO with `-Warc-repeated-use-of-weak` 2021-10-27 ynzhang Invalidate the host service before resetting the service map. 2021-10-25 albertbow Add reconnection logic if eDO host is constructed via device connection. 2021-10-18 ynzhang Fix an issue of encoding for some targets. 2021-08-06 haowoo Update to Xcode 12.5 and clean up Travis. 2021-07-09 mobile-devx-github-bot Don't prevent passing NULL to non-Objective-C pointer parameters. 2021-05-25 albertbow Correct return value of eDO class request to be nullable. 2021-04-29 albertbow Upgrade eDO deployment os target to 11.0. 2021-04-29 albertbow Create helper class to pass Codable pure Swift types through a remote call. 2021-04-28 albertbow Bump Travis xcode version to 12.0. 2021-03-12 albertbow Avoid always creating listening port on the temporary service. 2021-03-11 albertbow Clean up IWYU warnings for eDO code base. 2021-03-05 albertbow Adds one more test case for deadlock fix. 2021-03-04 albertbow Fix the deadlock caused by recursive eDO call from temporary host service. 2021-02-10 mobile-devx-github-bot Internal Change. 2021-01-14 tirodkar Update eDO comments. 2020-12-17 albertbow Fix remote invocation failure on EDOObject wrapped EDOWeakObject. 2020-12-09 albertbow Upgrade CHANGELOG and podspec for eDO 1.0.2 release. 2020-11-23 haowoo Retrieve block signatures directly from block headers. 2020-11-21 mobile-devx-github-bot Add signature to blocks in EDO Created with: roll-dep crashpad/third_party/edo/edo Change-Id: I1fbb78652893e6f334e22902b3bafe4df9d3f173 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3550546 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- DEPS | 2 +- third_party/edo/BUILD.gn | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/DEPS b/DEPS index 5dd3d46fd3..6c4cd0c157 100644 --- a/DEPS +++ b/DEPS @@ -28,7 +28,7 @@ deps = { '9e121212d42be62a7cce38072f925f8398d11e49', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + - '6ffbf833173f53fcd06ecf08670a95cc01c01f72', + '727e556705278598fce683522beedbb9946bfda0', 'condition': 'checkout_ios', }, 'crashpad/third_party/googletest/googletest': diff --git a/third_party/edo/BUILD.gn b/third_party/edo/BUILD.gn index 73dca1aab4..ea6e9d38b4 100644 --- a/third_party/edo/BUILD.gn +++ b/third_party/edo/BUILD.gn @@ -7,9 +7,7 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_chromium) { group("edo") { testonly = true - public_deps = [ - "//ios/third_party/edo", - ] + public_deps = [ "//ios/third_party/edo" ] } } else { config("config") { @@ -103,6 +101,8 @@ if (crashpad_is_in_chromium) { "edo/Service/Sources/EDORemoteException.m", "edo/Service/Sources/EDORemoteVariable.h", "edo/Service/Sources/EDORemoteVariable.m", + "edo/Service/Sources/EDORuntimeUtils.h", + "edo/Service/Sources/EDORuntimeUtils.m", "edo/Service/Sources/EDOServiceError.h", "edo/Service/Sources/EDOServiceError.m", "edo/Service/Sources/EDOServiceException.h", @@ -139,8 +139,6 @@ if (crashpad_is_in_chromium) { ] public_configs = [ ":config" ] - deps = [ - "../../build:ios_enable_arc", - ] + deps = [ "../../build:ios_enable_arc" ] } } From 20d6dee0374e9f42616630f75c1afe6cf998f183 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 25 Mar 2022 22:16:27 -0400 Subject: [PATCH 141/478] Roll crashpad/third_party/googletest/googletest/ 5bcd8e3bb..af29db7ec (148 commits) https://chromium.googlesource.com/external/github.com/google/googletest/+log/5bcd8e3bb929..af29db7ec28d $ git log 5bcd8e3bb..af29db7ec --date=short --no-merges --format='%ad %ae %s' 2022-03-23 absl-team Address deprecation warning surfaced by Github presubmit tests 2022-03-23 mattias.ellert Split gmock-matchers_test into 4 smaller test #3653 2022-03-22 absl-team Only print disabled test banner if the test matches gtest_filter 2022-03-21 absl-team Clarify public access on gmock examples. 2022-03-18 bmesser Remove sanity as it is offensive to neurodiverse individuals. 2022-03-15 absl-team Running clang-format over all of GoogleTest 2022-03-14 dinor Remove references to deleted script gen_gtest_pred_impl.py 2022-03-08 absl-team Mark ACTION_Pn()-generated functions as must-use-result, adding non-compilation tests. 2022-03-08 sobik.szymon Add myself to contributors 2022-03-08 sobik.szymon Adjust documentation regarding xml and json source file location otput. 2022-03-08 sobik.szymon Adjust xml and json unit tests to test for source file and line location. 2022-03-08 sobik.szymon Add support for testing of xml and json output of source file and line location 2022-03-08 sobik.szymon Output source file path and line number in xml and json files. 2022-02-17 dmauro Update GCC/Clang Linux tests to use Bazel 5.0.0 2022-02-14 absl-team Address conversion warning by explicitly casting to size_t 2022-02-09 absl-team Add a 3-arg overload for ResultOf() matcher that takes a description string for better error messages. 2022-02-05 hgsilverman Apply requested changes by using std::inserter with move. 2022-02-05 noiseless-ak Fix gtest-help-test failure on OpenBSD 2022-02-01 absl-team GetCurrentOsStackTraceExceptTop (both the method of UnitTestImpl and the wrapper function in gtest.cc) rely on the fact that the inner call is not getting optimized. This CL annotates them with the appropriate attributes. 2022-01-29 hgsilverman Do constant time matching for exact match filters. 2022-01-28 dmauro Finish some missed pieces of the TestCase to TestSuite Migration 2022-01-26 dinor Change `ReturnArg` to use perfect forwarding of arguments (#3733) 2022-01-25 melroy Let me give a change to try it again - updating to latest version 2022-01-24 absl-team Make recreate_environments_when_repeating=false the default. 2022-01-19 absl-team Factor out AssertionResult into dedicated gtest-assertion-result header + implementation files to prevent cyclic includes between gtest.h and gtest_pred_impl.h 2022-01-18 absl-team Consistently apply IWYU pragmas across googletest and googlemock headers 2022-01-14 dinor Fix reference to source file in gmock FAQ 2022-01-14 dmauro Update test Docker image to GCC 11.2, Clang 14 (prerelease), CMake 3.22.1, and Bazel 4.2.2 2022-01-13 ayush854032 FIX #2174 -- remove `DEBUG_POSTFIX` 2022-01-12 absl-team Fix run-on sentence 2022-01-06 hgsilverman Fix a typo in comments. 2021-12-22 hgsilverman Use normal for loop instead of accumulate. 2021-12-17 hgsilverman Improve code readablity. 2021-12-17 hgsilverman Apply requested changes to preserve old behavior. 2021-12-03 hgsilverman Reimplement MatchesFilter with new interfaces. 2021-11-23 hgsilverman Apply requested changes. 2021-10-17 hgsilverman Get rid of redundant filter matching code 2021-10-17 hgsilverman Add comments describing the behavior of filters 2021-10-17 hgsilverman Process filter string once instead of per test 2022-01-05 bsilver16384 Remove another GTEST_DISALLOW_ASSIGN_ that crept in 2022-01-05 73706994+jjfvanderpol Set CMake Policy CMP0077 to NEW 2022-01-04 4789010+ramkumar-kr Update example to reflect the tests below 2022-01-01 ayush854032 FIX #3719 -- Fix `clang` conversion warnings 2021-12-27 absl-team Include the param names in the generated description of the MATCHER_P matchers. 2021-12-22 absl-team Clarify "package" means "Bazel package", and promote `testonly=True` rather than `testing` sub-directory. 2021-12-22 dmauro Makes the Python imports consistently use full paths from the repository root, unifying the behavior between Bazel and CMake 2021-12-21 dmauro Makes TestForDeathTest.CRTDebugDeath only run when _DEBUG is defined 2021-12-21 philip.j.m link to regex on qnx in cmake 2021-12-15 dinor Release tests for UnitTestOptions::MatchesFilter 2021-12-07 absl-team Add NOLINT to address modernize-use-trailing-return-type in TEST_F uses (...) 2021-09-14 absl-team Googletest export 2021-09-15 761129+derekmauro Revert grammatically incorrect change 2021-09-10 absl-team Googletest export 2021-08-20 absl-team Googletest export 2021-08-20 absl-team Googletest export 2021-08-19 invalid_ms_user Simplify example code with c++11 2021-08-12 absl-team Googletest export 2021-08-10 dmauro Googletest export 2021-08-09 dmauro Googletest export 2021-08-10 akashkumarsingh11032001 add a missing 'a' 2021-08-10 akashkumarsingh11032001 Create CONTRIBUTING.md 2021-08-06 absl-team Internal change 2021-08-06 victordk13 Format test properties in xml printer 2021-08-05 iamberkeyavas typo fix gmock_cook_book 2021-08-03 absl-team Googletest export 2021-08-03 absl-team Googletest export 2021-08-02 absl-team Googletest export 2021-07-29 absl-team Googletest export 2021-07-29 otnaiud Typo, double "the" 2021-07-28 absl-team Internal change 2021-07-24 slowy.arfy fix: typo codespelling comment 2021-07-22 absl-team Googletest export 2021-07-21 absl-team Googletest export 2021-07-19 dmauro Googletest export 2021-07-14 761129+derekmauro Fix location of GOOGLETEST_CM0011 marker 2021-07-08 absl-team Googletest export 2021-07-08 absl-team Googletest export 2021-07-07 absl-team Googletest export 2021-07-02 absl-team Googletest export 2021-07-02 absl-team Googletest export 2021-07-07 manuel Link -lregex on QNX 2021-07-01 jeremy.nimmer Use GTEST_DONT_DEFINE_TEST_F to guard TEST_F 2021-06-29 absl-team Googletest export 2021-06-28 absl-team Googletest export 2021-06-28 absl-team Googletest export 2021-06-25 manuel Don't link pthread on QNX 2021-06-23 alex Fix EXPECT_DEATH() and ASSERT_DEATH() triggering -Wcovered-switch-default 2021-06-18 dmauro Googletest export 2021-06-03 pochkaenkov feat: make a matcher ElementsAreArray applicable for std ranges 2021-06-13 hyuk.myeong fix typos 2021-06-11 absl-team Googletest export 2021-06-10 absl-team Googletest export 2021-06-09 absl-team Googletest export 2021-06-09 dmauro Googletest export 2021-06-09 absl-team Googletest export 2021-06-09 absl-team Googletest export 2021-06-08 absl-team Googletest export 2020-12-30 mattias.ellert Port to GNU/Hurd 2020-12-29 julien.jemine Using auto instead of container::const_iterator 2020-12-24 georgthegreat Use proper feature test macro to test if library supports char8_t Created with: roll-dep crashpad/third_party/googletest/googletest Change-Id: I34a2d997498b73a17ee9ee71db45081f2ebab9a4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3553800 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- DEPS | 2 +- third_party/googletest/BUILD.gn | 34 +++++++++++++++++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/DEPS b/DEPS index 6c4cd0c157..2f8a2e6400 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { }, 'crashpad/third_party/googletest/googletest': Var('chromium_git') + '/external/github.com/google/googletest@' + - '5bcd8e3bb929714e031a542d303f818e5a5af45d', + 'af29db7ec28d6df1c7f0f745186884091e602e07', 'crashpad/third_party/lss/lss': Var('chromium_git') + '/linux-syscall-support.git@' + 'e1e7b0ad8ee99a875b272c8e33e308472e897660', diff --git a/third_party/googletest/BUILD.gn b/third_party/googletest/BUILD.gn index 6d98a38ba0..2cfb508929 100644 --- a/third_party/googletest/BUILD.gn +++ b/third_party/googletest/BUILD.gn @@ -55,6 +55,7 @@ if (crashpad_is_in_chromium) { static_library("googletest") { testonly = true sources = [ + "$googletest_dir/googletest/include/gtest/gtest-assertion-result.h", "$googletest_dir/googletest/include/gtest/gtest-death-test.h", "$googletest_dir/googletest/include/gtest/gtest-matchers.h", "$googletest_dir/googletest/include/gtest/gtest-message.h", @@ -78,6 +79,7 @@ if (crashpad_is_in_chromium) { "$googletest_dir/googletest/include/gtest/internal/gtest-string.h", "$googletest_dir/googletest/include/gtest/internal/gtest-type-util.h", "$googletest_dir/googletest/src/gtest-all.cc", + "$googletest_dir/googletest/src/gtest-assertion-result.cc", "$googletest_dir/googletest/src/gtest-death-test.cc", "$googletest_dir/googletest/src/gtest-filepath.cc", "$googletest_dir/googletest/src/gtest-internal-inl.h", @@ -176,14 +178,6 @@ if (crashpad_is_in_chromium) { configs -= [ "$mini_chromium_dir/build/config:Wexit_time_destructors" ] configs += [ ":googletest_private_config" ] deps = [ ":googletest" ] - - if (crashpad_is_clang) { - cflags_cc = [ - # For googletest/googlemock/test/gmock-matchers_test.cc’s - # Unstreamable::value_. - "-Wno-unused-private-field", - ] - } } test("gtest_premature_exit_test") { @@ -299,7 +293,11 @@ if (crashpad_is_in_chromium) { "$googletest_dir/googlemock/test/gmock-cardinalities_test.cc", "$googletest_dir/googlemock/test/gmock-function-mocker_test.cc", "$googletest_dir/googlemock/test/gmock-internal-utils_test.cc", - "$googletest_dir/googlemock/test/gmock-matchers_test.cc", + "$googletest_dir/googlemock/test/gmock-matchers-arithmetic_test.cc", + "$googletest_dir/googlemock/test/gmock-matchers-comparisons_test.cc", + "$googletest_dir/googlemock/test/gmock-matchers-containers_test.cc", + "$googletest_dir/googlemock/test/gmock-matchers-misc_test.cc", + "$googletest_dir/googlemock/test/gmock-matchers_test.h", "$googletest_dir/googlemock/test/gmock-more-actions_test.cc", "$googletest_dir/googlemock/test/gmock-nice-strict_test.cc", "$googletest_dir/googlemock/test/gmock-port_test.cc", @@ -324,17 +322,21 @@ if (crashpad_is_in_chromium) { # always use the override modifier with MOCK_METHOD. "-Wno-inconsistent-missing-override", - # For googletest/googlemock/test/gmock-matchers_test.cc’s - # testing::googlemock_matchers_test::Unprintable::c_ and deprecated - # std::iterator. - "-Wno-unused-private-field", - "-Wno-deprecated-declarations", + # For googlemock/test/gmock-matchers-misc_test.cc comparison of + # integers of different signs. + "-Wno-sign-compare", ] } if (crashpad_is_win) { - # TODO: Correct SDK in vc\tools\msvc\14.14.26428\include\functional - cflags = [ "/wd4789" ] # VAR of size N bytes will be overrun + cflags = [ + # TODO: Correct SDK in vc\tools\msvc\14.14.26428\include\functional + "/wd4789", # VAR of size N bytes will be overrun + + # For googlemock/test/gmock-matchers-misc_test.cc comparison of + # integers of different signs. + "/wd4018", + ] } } From fa01762894a340fea214f3f7660262f223a1dcc7 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 31 Mar 2022 13:50:10 -0400 Subject: [PATCH 142/478] ios: Update build scripts to support Apple Silicon simulators. Also update mini_chromium to 5654edb422 for target_environment arg. Change-Id: If350938bbeaddbdda123c2f0e9ff978075a60370 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3558170 Reviewed-by: Rohit Rao Commit-Queue: Justin Cohen --- DEPS | 2 +- build/ios/convert_gn_xcodeproj.py | 334 +++++++--- build/ios/setup_ios_gn.py | 626 ++++++++++--------- build/ios/xcodescheme-testable.template | 10 + build/ios/xcodescheme.template | 80 +++ test/ios/host/cptest_application_delegate.mm | 13 +- 6 files changed, 710 insertions(+), 355 deletions(-) create mode 100644 build/ios/xcodescheme-testable.template create mode 100644 build/ios/xcodescheme.template diff --git a/DEPS b/DEPS index 2f8a2e6400..229922376b 100644 --- a/DEPS +++ b/DEPS @@ -39,7 +39,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'f87a38442a9e7ba88d1c4f479e9167927eae84ed', + '5654edb4225bcad13901155c819febb5748e502b', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py index 48c1752506..8c5c6d073f 100755 --- a/build/ios/convert_gn_xcodeproj.py +++ b/build/ios/convert_gn_xcodeproj.py @@ -26,14 +26,146 @@ import collections import copy import filecmp -import json +import functools import hashlib +import json import os import re import shutil +import string import subprocess import sys import tempfile +import xml.etree.ElementTree + + +LLDBINIT_PATH = '$(PROJECT_DIR)/.lldbinit' + +PYTHON_RE = re.compile('[ /]python[23]?$') + +XCTEST_PRODUCT_TYPES = frozenset(( + 'com.apple.product-type.bundle.unit-test', + 'com.apple.product-type.bundle.ui-testing', +)) + +SCHEME_PRODUCT_TYPES = frozenset(( + 'com.apple.product-type.app-extension', + 'com.apple.product-type.application', + 'com.apple.product-type.framework' +)) + + +class Template(string.Template): + + """A subclass of string.Template that changes delimiter.""" + + delimiter = '@' + + +@functools.lru_cache +def LoadSchemeTemplate(root, name): + """Return a string.Template object for scheme file loaded relative to root.""" + path = os.path.join(root, 'build', 'ios', name) + with open(path) as file: + return Template(file.read()) + + +def CreateIdentifier(str_id): + """Return a 24 characters string that can be used as an identifier.""" + return hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper() + + +def GenerateSchemeForTarget(root, project, old_project, name, path, tests): + """Generates the .xcsheme file for target named |name|. + + The file is generated in the new project schemes directory from a template. + If there is an existing previous project, then the old scheme file is copied + and the lldbinit setting is set. If lldbinit setting is already correct, the + file is not modified, just copied. + """ + project_name = os.path.basename(project) + relative_path = os.path.join('xcshareddata', 'xcschemes', name + '.xcscheme') + identifier = CreateIdentifier('%s %s' % (name, path)) + + scheme_path = os.path.join(project, relative_path) + if not os.path.isdir(os.path.dirname(scheme_path)): + os.makedirs(os.path.dirname(scheme_path)) + + old_scheme_path = os.path.join(old_project, relative_path) + if os.path.exists(old_scheme_path): + made_changes = False + + tree = xml.etree.ElementTree.parse(old_scheme_path) + tree_root = tree.getroot() + + for reference in tree_root.findall('.//BuildableReference'): + for (attr, value) in ( + ('BuildableName', path), + ('BlueprintName', name), + ('BlueprintIdentifier', identifier)): + if reference.get(attr) != value: + reference.set(attr, value) + made_changes = True + + for child in tree_root: + if child.tag not in ('TestAction', 'LaunchAction'): + continue + + if child.get('customLLDBInitFile') != LLDBINIT_PATH: + child.set('customLLDBInitFile', LLDBINIT_PATH) + made_changes = True + + # Override the list of testables. + if child.tag == 'TestAction': + for subchild in child: + if subchild.tag != 'Testables': + continue + + for elt in list(subchild): + subchild.remove(elt) + + if tests: + template = LoadSchemeTemplate(root, 'xcodescheme-testable.template') + for (key, test_path, test_name) in sorted(tests): + testable = ''.join(template.substitute( + BLUEPRINT_IDENTIFIER=key, + BUILDABLE_NAME=test_path, + BLUEPRINT_NAME=test_name, + PROJECT_NAME=project_name)) + + testable_elt = xml.etree.ElementTree.fromstring(testable) + subchild.append(testable_elt) + + if made_changes: + tree.write(scheme_path, xml_declaration=True, encoding='UTF-8') + + else: + shutil.copyfile(old_scheme_path, scheme_path) + + else: + + testables = '' + if tests: + template = LoadSchemeTemplate(root, 'xcodescheme-testable.template') + testables = '\n' + ''.join( + template.substitute( + BLUEPRINT_IDENTIFIER=key, + BUILDABLE_NAME=test_path, + BLUEPRINT_NAME=test_name, + PROJECT_NAME=project_name) + for (key, test_path, test_name) in sorted(tests)).rstrip() + + template = LoadSchemeTemplate(root, 'xcodescheme.template') + + with open(scheme_path, 'w') as scheme_file: + scheme_file.write( + template.substitute( + TESTABLES=testables, + LLDBINIT_PATH=LLDBINIT_PATH, + BLUEPRINT_IDENTIFIER=identifier, + BUILDABLE_NAME=path, + BLUEPRINT_NAME=name, + PROJECT_NAME=project_name)) class XcodeProject(object): @@ -46,7 +178,7 @@ def AddObject(self, parent_name, obj): while True: self.counter += 1 str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter) - new_id = hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper() + new_id = CreateIdentifier(str_id) # Make sure ID is unique. It's possible there could be an id conflict # since this is run after GN runs. @@ -54,6 +186,93 @@ def AddObject(self, parent_name, obj): self.objects[new_id] = obj return new_id + def IterObjectsByIsa(self, isa): + """Iterates overs objects of the |isa| type.""" + for key, obj in self.objects.items(): + if obj['isa'] == isa: + yield (key, obj) + + def IterNativeTargetByProductType(self, product_types): + """Iterates over PBXNativeTarget objects of any |product_types| types.""" + for key, obj in self.IterObjectsByIsa('PBXNativeTarget'): + if obj['productType'] in product_types: + yield (key, obj) + + def UpdateBuildScripts(self): + """Update build scripts to respect configuration and platforms.""" + for key, obj in self.IterObjectsByIsa('PBXShellScriptBuildPhase'): + + shell_path = obj['shellPath'] + shell_code = obj['shellScript'] + if shell_path.endswith('/sh'): + shell_code = shell_code.replace( + 'ninja -C .', + 'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"') + elif PYTHON_RE.search(shell_path): + shell_code = shell_code.replace( + '''ninja_params = [ '-C', '.' ]''', + '''ninja_params = [ '-C', '../' + os.environ['CONFIGURATION']''' + ''' + os.environ['EFFECTIVE_PLATFORM_NAME'] ]''') + + # Replace the build script in the object. + obj['shellScript'] = shell_code + + + def UpdateBuildConfigurations(self, configurations): + """Add new configurations, using the first one as default.""" + + # Create a list with all the objects of interest. This is needed + # because objects will be added to/removed from the project upon + # iterating this list and python dictionaries cannot be mutated + # during iteration. + for key, obj in list(self.IterObjectsByIsa('XCConfigurationList')): + # Use the first build configuration as template for creating all the + # new build configurations. + build_config_template = self.objects[obj['buildConfigurations'][0]] + build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \ + '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)' + + + # Remove the existing build configurations from the project before + # creating the new ones. + for build_config_id in obj['buildConfigurations']: + del self.objects[build_config_id] + obj['buildConfigurations'] = [] + + for configuration in configurations: + build_config = copy.copy(build_config_template) + build_config['name'] = configuration + build_config_id = self.AddObject('products', build_config) + obj['buildConfigurations'].append(build_config_id) + + def GetHostMappingForXCTests(self): + """Returns a dict from targets to the list of their xctests modules.""" + mapping = collections.defaultdict(list) + for key, obj in self.IterNativeTargetByProductType(XCTEST_PRODUCT_TYPES): + build_config_lists_id = obj['buildConfigurationList'] + build_configs = self.objects[build_config_lists_id]['buildConfigurations'] + + # Use the first build configuration to get the name of the host target. + # This is arbitrary, but since the build configuration are all identical + # after UpdateBuildConfiguration, except for their 'name', it is fine. + build_config = self.objects[build_configs[0]] + if obj['productType'] == 'com.apple.product-type.bundle.unit-test': + # The test_host value will look like this: + # `$(BUILD_PRODUCTS_DIR)/host_app_name.app/host_app_name` + # + # Extract the `host_app_name.app` part as key for the output. + test_host_path = build_config['buildSettings']['TEST_HOST'] + test_host_name = os.path.basename(os.path.dirname(test_host_path)) + else: + test_host_name = build_config['buildSettings']['TEST_TARGET_NAME'] + + test_name = obj['name'] + test_path = self.objects[obj['productReference']]['path'] + + mapping[test_host_name].append((key, test_name, test_path)) + + return dict(mapping) + def check_output(command): """Wrapper around subprocess.check_output that decode output as utf-8.""" @@ -100,7 +319,7 @@ def WriteXcodeProject(output_path, json_string): os.path.join(output_path, 'project.pbxproj')) -def UpdateXcodeProject(project_dir, configurations, root_dir): +def UpdateXcodeProject(project_dir, old_project_dir, configurations, root_dir): """Update inplace Xcode project to support multiple configurations. Args: @@ -113,41 +332,25 @@ def UpdateXcodeProject(project_dir, configurations, root_dir): json_data = json.loads(LoadXcodeProjectAsJSON(project_dir)) project = XcodeProject(json_data['objects']) - objects_to_remove = [] - for value in list(project.objects.values()): - isa = value['isa'] + project.UpdateBuildScripts() + project.UpdateBuildConfigurations(configurations) - # Teach build shell script to look for the configuration and platform. - if isa == 'PBXShellScriptBuildPhase': - shell_path = value['shellPath'] - if shell_path.endswith('/sh'): - value['shellScript'] = value['shellScript'].replace( - 'ninja -C .', - 'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"') - elif re.search('[ /]python[23]?$', shell_path): - value['shellScript'] = value['shellScript'].replace( - 'ninja_params = [ \'-C\', \'.\' ]', - 'ninja_params = [ \'-C\', \'../\' + os.environ[\'CONFIGURATION\']' - ' + os.environ[\'EFFECTIVE_PLATFORM_NAME\'] ]') - - # Add new configuration, using the first one as default. - if isa == 'XCConfigurationList': - value['defaultConfigurationName'] = configurations[0] - objects_to_remove.extend(value['buildConfigurations']) - - build_config_template = project.objects[value['buildConfigurations'][0]] - build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \ - '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)' + mapping = project.GetHostMappingForXCTests() - value['buildConfigurations'] = [] - for configuration in configurations: - new_build_config = copy.copy(build_config_template) - new_build_config['name'] = configuration - value['buildConfigurations'].append( - project.AddObject('products', new_build_config)) + # Generate schemes for application, extensions and framework targets + for key, obj in project.IterNativeTargetByProductType(SCHEME_PRODUCT_TYPES): + product = project.objects[obj['productReference']] + product_path = product['path'] + + # For XCTests, the key is the product path, while for XCUITests, the key + # is the target name. Use a sum of both possible keys (there should not + # be overlaps since different hosts are used for XCTests and XCUITests + # but this make the code simpler). + tests = mapping.get(product_path, []) + mapping.get(obj['name'], []) + GenerateSchemeForTarget( + root_dir, project_dir, old_project_dir, + obj['name'], product_path, tests) - for object_id in objects_to_remove: - del project.objects[object_id] source = GetOrCreateRootGroup(project, json_data['rootObject'], 'Source') AddMarkdownToProject(project, root_dir, source) @@ -274,7 +477,7 @@ def GetFolderForPath(project, group_object, path): return group_object -def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations): +def ConvertGnXcodeProject(root_dir, proj_name, input_dir, output_dir, configs): '''Tweak the Xcode project generated by gn to support multiple configurations. The Xcode projects generated by "gn gen --ide" only supports a single @@ -284,34 +487,22 @@ def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations): to select them in Xcode). Args: + root_dir: directory that is the root of the project + proj_name: name of the Xcode project "file" (usually `all.xcodeproj`) input_dir: directory containing the XCode projects created by "gn gen --ide" output_dir: directory where the tweaked Xcode projects will be saved - configurations: list of string corresponding to the configurations that - need to be supported by the tweaked Xcode projects, must contains at - least one value. + configs: list of string corresponding to the configurations that need to be + supported by the tweaked Xcode projects, must contains at least one + value. ''' - # Update the project (supports legacy name "products.xcodeproj" or the new - # project name "all.xcodeproj"). - for project_name in ('all.xcodeproj', 'products.xcodeproj'): - if os.path.exists(os.path.join(input_dir, project_name)): - UpdateXcodeProject( - os.path.join(input_dir, project_name), - configurations, root_dir) + UpdateXcodeProject( + os.path.join(input_dir, proj_name), + os.path.join(output_dir, proj_name), + configs, root_dir) - CopyTreeIfChanged(os.path.join(input_dir, project_name), - os.path.join(output_dir, project_name)) - - else: - shutil.rmtree(os.path.join(output_dir, project_name), ignore_errors=True) - - # Copy all.xcworkspace if it exists (will be removed in a future gn version). - workspace_name = 'all.xcworkspace' - if os.path.exists(os.path.join(input_dir, workspace_name)): - CopyTreeIfChanged(os.path.join(input_dir, workspace_name), - os.path.join(output_dir, workspace_name)) - else: - shutil.rmtree(os.path.join(output_dir, workspace_name), ignore_errors=True) + CopyTreeIfChanged(os.path.join(input_dir, proj_name), + os.path.join(output_dir, proj_name)) def Main(args): @@ -329,33 +520,30 @@ def Main(args): parser.add_argument( '--root', type=os.path.abspath, required=True, help='root directory of the project') + parser.add_argument( + '--project-name', default='all.xcodeproj', dest='proj_name', + help='name of the Xcode project (default: %(default)s)') args = parser.parse_args(args) if not os.path.isdir(args.input): sys.stderr.write('Input directory does not exists.\n') return 1 - # Depending on the version of "gn", there should be either one project file - # named "all.xcodeproj" or a project file named "products.xcodeproj" and a - # workspace named "all.xcworkspace". - required_files_sets = [ - set(("all.xcodeproj",)), - set(("products.xcodeproj", "all.xcworkspace")), - ] - - for required_files in required_files_sets: - if required_files.issubset(os.listdir(args.input)): - break - else: + if args.proj_name not in os.listdir(args.input): sys.stderr.write( - 'Input directory does not contain all necessary Xcode projects.\n') + 'Input directory does not contain the Xcode project.\n') return 1 if not args.configurations: sys.stderr.write('At least one configuration required, see --add-config.\n') return 1 - ConvertGnXcodeProject(args.root, args.input, args.output, args.configurations) + ConvertGnXcodeProject( + args.root, + args.proj_name, + args.input, + args.output, + args.configurations) if __name__ == '__main__': sys.exit(Main(sys.argv[1:])) diff --git a/build/ios/setup_ios_gn.py b/build/ios/setup_ios_gn.py index 76e6381176..aacc8ec7bd 100755 --- a/build/ios/setup_ios_gn.py +++ b/build/ios/setup_ios_gn.py @@ -15,325 +15,391 @@ # limitations under the License. import argparse +import configparser import convert_gn_xcodeproj import errno +import io import os +import platform import re import shutil import subprocess import sys import tempfile -import configparser -import io -SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator') -SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage') + +SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator', 'maccatalyst') +SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official') + +# Pattern matching lines from ~/.lldbinit that must not be copied to the +# generated .lldbinit file. They match what the user were told to add to +# their global ~/.lldbinit file before setup-gn.py was updated to generate +# a project specific file and thus must not be copied as they would cause +# the settings to be overwritten. +LLDBINIT_SKIP_PATTERNS = ( + re.compile('^script sys.path\\[:0\\] = \\[\'.*/src/tools/lldb\'\\]$'), + re.compile('^script import lldbinit$'), + re.compile('^settings append target.source-map .* /google/src/.*$'), +) + + +def HostCpuArch(): + '''Returns the arch of the host cpu for GN.''' + HOST_CPU_ARCH = { + 'arm64': '"arm64"', + 'x86_64': '"x64"', + } + return HOST_CPU_ARCH[platform.machine()] class ConfigParserWithStringInterpolation(configparser.ConfigParser): - '''A .ini file parser that supports strings and environment variables.''' - ENV_VAR_PATTERN = re.compile(r'\$([A-Za-z0-9_]+)') + '''A .ini file parser that supports strings and environment variables.''' - def values(self, section): - return [self._UnquoteString(self._ExpandEnvVar(kv[1])) for kv in configparser.ConfigParser.items(self, section)] + ENV_VAR_PATTERN = re.compile(r'\$([A-Za-z0-9_]+)') - def getstring(self, section, option): - return self._UnquoteString(self._ExpandEnvVar(self.get(section, - option))) + def values(self, section): + return filter( + lambda val: val != '', + map(lambda kv: self._UnquoteString(self._ExpandEnvVar(kv[1])), + configparser.ConfigParser.items(self, section))) - def _UnquoteString(self, string): - if not string or string[0] != '"' or string[-1] != '"': - return string - return string[1:-1] + def getstring(self, section, option, fallback=''): + try: + raw_value = self.get(section, option) + except configparser.NoOptionError: + return fallback + return self._UnquoteString(self._ExpandEnvVar(raw_value)) - def _ExpandEnvVar(self, value): - match = self.ENV_VAR_PATTERN.search(value) - if not match: - return value - name, (begin, end) = match.group(1), match.span(0) - prefix, suffix = value[:begin], self._ExpandEnvVar(value[end:]) - return prefix + os.environ.get(name, '') + suffix + def _UnquoteString(self, string): + if not string or string[0] != '"' or string[-1] != '"': + return string + return string[1:-1] + + def _ExpandEnvVar(self, value): + match = self.ENV_VAR_PATTERN.search(value) + if not match: + return value + name, (begin, end) = match.group(1), match.span(0) + prefix, suffix = value[:begin], self._ExpandEnvVar(value[end:]) + return prefix + os.environ.get(name, '') + suffix class GnGenerator(object): - '''Holds configuration for a build and method to generate gn default - files.''' - - FAT_BUILD_DEFAULT_ARCH = '64-bit' - - TARGET_CPU_VALUES = { - 'iphoneos': { - '32-bit': '"arm"', - '64-bit': '"arm64"', - }, - 'iphonesimulator': { - '32-bit': '"x86"', - '64-bit': '"x64"', - } - } - - def __init__(self, settings, config, target): - assert target in SUPPORTED_TARGETS - assert config in SUPPORTED_CONFIGS - self._settings = settings - self._config = config - self._target = target - - def _GetGnArgs(self): - """Build the list of arguments to pass to gn. - - Returns: - A list of tuple containing gn variable names and variable values (it - is not a dictionary as the order needs to be preserved). - """ - args = [] - - args.append(('is_debug', self._config in ('Debug', 'Coverage'))) - - if os.environ.get('FORCE_MAC_TOOLCHAIN', '0') == '1': - args.append(('use_system_xcode', False)) - - cpu_values = self.TARGET_CPU_VALUES[self._target] - build_arch = self._settings.getstring('build', 'arch') - if build_arch == 'fat': - target_cpu = cpu_values[self.FAT_BUILD_DEFAULT_ARCH] - args.append(('target_cpu', target_cpu)) - args.append( - ('additional_target_cpus', - [cpu for cpu in cpu_values.values() if cpu != target_cpu])) - else: - args.append(('target_cpu', cpu_values[build_arch])) - - # Add user overrides after the other configurations so that they can - # refer to them and override them. - args.extend(self._settings.items('gn_args')) - return args - - def Generate(self, gn_path, root_path, out_path): - buf = io.StringIO() - self.WriteArgsGn(buf) - WriteToFileIfChanged(os.path.join(out_path, 'args.gn'), - buf.getvalue(), - overwrite=True) - - subprocess.check_call( - self.GetGnCommand(gn_path, root_path, out_path, True)) - - def CreateGnRules(self, gn_path, root_path, out_path): - buf = io.StringIO() - self.WriteArgsGn(buf) - WriteToFileIfChanged(os.path.join(out_path, 'args.gn'), - buf.getvalue(), - overwrite=True) - - buf = io.StringIO() - gn_command = self.GetGnCommand(gn_path, root_path, out_path, False) - self.WriteBuildNinja(buf, gn_command) - WriteToFileIfChanged(os.path.join(out_path, 'build.ninja'), - buf.getvalue(), - overwrite=False) - - buf = io.StringIO() - self.WriteBuildNinjaDeps(buf) - WriteToFileIfChanged(os.path.join(out_path, 'build.ninja.d'), - buf.getvalue(), - overwrite=False) - - def WriteArgsGn(self, stream): - stream.write('# This file was generated by setup-gn.py. Do not edit\n') - stream.write('# but instead use ~/.setup-gn or $repo/.setup-gn files\n') - stream.write('# to configure settings.\n') - stream.write('\n') + '''Holds configuration for a build and method to generate gn default files.''' + + FAT_BUILD_DEFAULT_ARCH = '64-bit' + + TARGET_CPU_VALUES = { + 'iphoneos': '"arm64"', + 'iphonesimulator': HostCpuArch(), + 'maccatalyst': HostCpuArch(), + } + + TARGET_ENVIRONMENT_VALUES = { + 'iphoneos': '"device"', + 'iphonesimulator': '"simulator"', + 'maccatalyst': '"catalyst"' + } + + def __init__(self, settings, config, target): + assert target in SUPPORTED_TARGETS + assert config in SUPPORTED_CONFIGS + self._settings = settings + self._config = config + self._target = target + + def _GetGnArgs(self, extra_args=None): + """Build the list of arguments to pass to gn. + + Returns: + A list of tuple containing gn variable names and variable values (it + is not a dictionary as the order needs to be preserved). + """ + args = [] + + is_debug = self._config == 'Debug' + official = self._config == 'Official' + is_optim = self._config in ('Profile', 'Official') + + args.append(('target_os', '"ios"')) + args.append(('is_debug', is_debug)) + + if os.environ.get('FORCE_MAC_TOOLCHAIN', '0') == '1': + args.append(('use_system_xcode', False)) + + args.append(('target_cpu', self.TARGET_CPU_VALUES[self._target])) + args.append(( + 'target_environment', + self.TARGET_ENVIRONMENT_VALUES[self._target])) + + # If extra arguments are passed to the function, pass them before the + # user overrides (if any). + if extra_args is not None: + args.extend(extra_args) + + # Add user overrides after the other configurations so that they can + # refer to them and override them. + args.extend(self._settings.items('gn_args')) + return args + + + def Generate(self, gn_path, proj_name, root_path, build_dir): + self.WriteArgsGn(build_dir, xcode_project_name=proj_name) + subprocess.check_call(self.GetGnCommand( + gn_path, root_path, build_dir, xcode_project_name=proj_name)) + + def CreateGnRules(self, gn_path, root_path, build_dir): + gn_command = self.GetGnCommand(gn_path, root_path, build_dir) + self.WriteArgsGn(build_dir) + self.WriteBuildNinja(gn_command, build_dir) + self.WriteBuildNinjaDeps(build_dir) + + def WriteArgsGn(self, build_dir, xcode_project_name=None): + with open(os.path.join(build_dir, 'args.gn'), 'w') as stream: + stream.write('# This file was generated by setup-gn.py. Do not edit\n') + stream.write('# but instead use ~/.setup-gn or $repo/.setup-gn files\n') + stream.write('# to configure settings.\n') + stream.write('\n') + + if self._target != 'maccatalyst': if self._settings.has_section('$imports$'): - for import_rule in self._settings.values('$imports$'): - stream.write('import("%s")\n' % import_rule) - stream.write('\n') - - gn_args = self._GetGnArgs() - for name, value in gn_args: - if isinstance(value, bool): - stream.write('%s = %s\n' % (name, str(value).lower())) - elif isinstance(value, list): - stream.write('%s = [%s' % - (name, '\n' if len(value) > 1 else '')) - if len(value) == 1: - prefix = ' ' - suffix = ' ' - else: - prefix = ' ' - suffix = ',\n' - for item in value: - if isinstance(item, bool): - stream.write('%s%s%s' % - (prefix, str(item).lower(), suffix)) - else: - stream.write('%s%s%s' % (prefix, item, suffix)) - stream.write(']\n') + for import_rule in self._settings.values('$imports$'): + stream.write('import("%s")\n' % import_rule) + stream.write('\n') + + gn_args = self._GetGnArgs() + + for name, value in gn_args: + if isinstance(value, bool): + stream.write('%s = %s\n' % (name, str(value).lower())) + elif isinstance(value, list): + stream.write('%s = [%s' % (name, '\n' if len(value) > 1 else '')) + if len(value) == 1: + prefix = ' ' + suffix = ' ' + else: + prefix = ' ' + suffix = ',\n' + for item in value: + if isinstance(item, bool): + stream.write('%s%s%s' % (prefix, str(item).lower(), suffix)) else: - stream.write('%s = %s\n' % (name, value)) - - def WriteBuildNinja(self, stream, gn_command): - stream.write('rule gn\n') - stream.write(' command = %s\n' % NinjaEscapeCommand(gn_command)) - stream.write(' description = Regenerating ninja files\n') - stream.write('\n') - stream.write('build build.ninja: gn\n') - stream.write(' generator = 1\n') - stream.write(' depfile = build.ninja.d\n') - - def WriteBuildNinjaDeps(self, stream): - stream.write('build.ninja: nonexistant_file.gn\n') - - def GetGnCommand(self, gn_path, src_path, out_path, generate_xcode_project): - gn_command = [gn_path, '--root=%s' % os.path.realpath(src_path), '-q'] - if generate_xcode_project: - gn_command.append('--ide=xcode') - gn_command.append('--ninja-executable=autoninja') - if self._settings.has_section('filters'): - target_filters = self._settings.values('filters') - if target_filters: - gn_command.append('--filters=%s' % ';'.join(target_filters)) + stream.write('%s%s%s' % (prefix, item, suffix)) + stream.write(']\n') else: - gn_command.append('--check') - gn_command.append('gen') - gn_command.append('//%s' % os.path.relpath(os.path.abspath(out_path), - os.path.abspath(src_path))) - return gn_command - - -def WriteToFileIfChanged(filename, content, overwrite): - '''Write |content| to |filename| if different. If |overwrite| is False - and the file already exists it is left untouched.''' - if os.path.exists(filename): - if not overwrite: - return - with open(filename) as file: - if file.read() == content: - return - if not os.path.isdir(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - with open(filename, 'w') as file: - file.write(content) + # ConfigParser removes quote around empty string which confuse + # `gn gen` so restore them. + if not value: + value = '""' + stream.write('%s = %s\n' % (name, value)) + + def WriteBuildNinja(self, gn_command, build_dir): + with open(os.path.join(build_dir, 'build.ninja'), 'w') as stream: + stream.write('ninja_required_version = 1.7.2\n') + stream.write('\n') + stream.write('rule gn\n') + stream.write(' command = %s\n' % NinjaEscapeCommand(gn_command)) + stream.write(' description = Regenerating ninja files\n') + stream.write('\n') + stream.write('build build.ninja: gn\n') + stream.write(' generator = 1\n') + stream.write(' depfile = build.ninja.d\n') + + def WriteBuildNinjaDeps(self, build_dir): + with open(os.path.join(build_dir, 'build.ninja.d'), 'w') as stream: + stream.write('build.ninja: nonexistant_file.gn\n') + + def GetGnCommand(self, gn_path, src_path, out_path, xcode_project_name=None): + gn_command = [ gn_path, '--root=%s' % os.path.realpath(src_path), '-q' ] + if xcode_project_name is not None: + gn_command.append('--ide=xcode') + gn_command.append('--ninja-executable=autoninja') + gn_command.append('--xcode-build-system=new') + gn_command.append('--xcode-project=%s' % xcode_project_name) + if self._settings.has_section('filters'): + target_filters = self._settings.values('filters') + if target_filters: + gn_command.append('--filters=%s' % ';'.join(target_filters)) + else: + gn_command.append('--check') + gn_command.append('gen') + gn_command.append('//%s' % + os.path.relpath(os.path.abspath(out_path), os.path.abspath(src_path))) + return gn_command def NinjaNeedEscape(arg): - '''Returns True if |arg| needs to be escaped when written to .ninja file.''' - return ':' in arg or '*' in arg or ';' in arg + '''Returns True if |arg| needs to be escaped when written to .ninja file.''' + return ':' in arg or '*' in arg or ';' in arg def NinjaEscapeCommand(command): - '''Escapes |command| in order to write it to .ninja file.''' - result = [] - for arg in command: - if NinjaNeedEscape(arg): - arg = arg.replace(':', '$:') - arg = arg.replace(';', '\\;') - arg = arg.replace('*', '\\*') - else: - result.append(arg) - return ' '.join(result) + '''Escapes |command| in order to write it to .ninja file.''' + result = [] + for arg in command: + if NinjaNeedEscape(arg): + arg = arg.replace(':', '$:') + arg = arg.replace(';', '\\;') + arg = arg.replace('*', '\\*') + else: + result.append(arg) + return ' '.join(result) def FindGn(): - '''Returns absolute path to gn binary looking at the PATH env variable.''' - for path in os.environ['PATH'].split(os.path.pathsep): - gn_path = os.path.join(path, 'gn') - if os.path.isfile(gn_path) and os.access(gn_path, os.X_OK): - return gn_path - return None - - -def GenerateXcodeProject(gn_path, root_dir, out_dir, settings): - '''Convert GN generated Xcode project into multi-configuration Xcode - project.''' - - temp_path = tempfile.mkdtemp( - prefix=os.path.abspath(os.path.join(out_dir, '_temp'))) - try: - generator = GnGenerator(settings, 'Debug', 'iphonesimulator') - generator.Generate(gn_path, root_dir, temp_path) - convert_gn_xcodeproj.ConvertGnXcodeProject( - root_dir, os.path.join(temp_path), os.path.join(out_dir, 'build'), - SUPPORTED_CONFIGS) - finally: - if os.path.exists(temp_path): - shutil.rmtree(temp_path) + '''Returns absolute path to gn binary looking at the PATH env variable.''' + for path in os.environ['PATH'].split(os.path.pathsep): + gn_path = os.path.join(path, 'gn') + if os.path.isfile(gn_path) and os.access(gn_path, os.X_OK): + return gn_path + return None + + +def GenerateXcodeProject(gn_path, root_dir, proj_name, out_dir, settings): + '''Generate Xcode project with Xcode and convert to multi-configurations.''' + prefix = os.path.abspath(os.path.join(out_dir, '_temp')) + temp_path = tempfile.mkdtemp(prefix=prefix) + try: + generator = GnGenerator(settings, 'Debug', 'iphonesimulator') + generator.Generate(gn_path, proj_name, root_dir, temp_path) + convert_gn_xcodeproj.ConvertGnXcodeProject( + root_dir, + '%s.xcodeproj' % proj_name, + os.path.join(temp_path), + os.path.join(out_dir, 'build'), + SUPPORTED_CONFIGS) + finally: + if os.path.exists(temp_path): + shutil.rmtree(temp_path) + +def CreateLLDBInitFile(root_dir, out_dir, settings): + ''' + Generate an .lldbinit file for the project that load the script that fixes + the mapping of source files (see docs/ios/build_instructions.md#debugging). + ''' + with open(os.path.join(out_dir, 'build', '.lldbinit'), 'w') as lldbinit: + lldb_script_dir = os.path.join(os.path.abspath(root_dir), 'tools', 'lldb') + lldbinit.write('script sys.path[:0] = [\'%s\']\n' % lldb_script_dir) + lldbinit.write('script import lldbinit\n') + + workspace_name = settings.getstring( + 'gn_args', + 'ios_internal_citc_workspace_name') + + if workspace_name != '': + username = os.environ['USER'] + for shortname in ('googlemac', 'third_party', 'blaze-out'): + lldbinit.write('settings append target.source-map %s %s\n' % ( + shortname, + '/google/src/cloud/%s/%s/google3/%s' % ( + username, workspace_name, shortname))) + + # Append the content of //ios/build/tools/lldbinit.defaults if it exists. + tools_dir = os.path.join(root_dir, 'ios', 'build', 'tools') + defaults_lldbinit_path = os.path.join(tools_dir, 'lldbinit.defaults') + if os.path.isfile(defaults_lldbinit_path): + with open(defaults_lldbinit_path) as defaults_lldbinit: + for line in defaults_lldbinit: + lldbinit.write(line) + + # Append the content of ~/.lldbinit if it exists. Line that look like they + # are trying to configure source mapping are skipped as they probably date + # back from when setup-gn.py was not generating an .lldbinit file. + global_lldbinit_path = os.path.join(os.environ['HOME'], '.lldbinit') + if os.path.isfile(global_lldbinit_path): + with open(global_lldbinit_path) as global_lldbinit: + for line in global_lldbinit: + if any(pattern.match(line) for pattern in LLDBINIT_SKIP_PATTERNS): + continue + lldbinit.write(line) def GenerateGnBuildRules(gn_path, root_dir, out_dir, settings): - '''Generates all template configurations for gn.''' - for config in SUPPORTED_CONFIGS: - for target in SUPPORTED_TARGETS: - build_dir = os.path.join(out_dir, '%s-%s' % (config, target)) - generator = GnGenerator(settings, config, target) - generator.CreateGnRules(gn_path, root_dir, build_dir) + '''Generates all template configurations for gn.''' + for config in SUPPORTED_CONFIGS: + for target in SUPPORTED_TARGETS: + build_dir = os.path.join(out_dir, '%s-%s' % (config, target)) + if not os.path.isdir(build_dir): + os.makedirs(build_dir) + generator = GnGenerator(settings, config, target) + generator.CreateGnRules(gn_path, root_dir, build_dir) -def Main(args): - default_root = os.path.normpath( - os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) - - parser = argparse.ArgumentParser( - description='Generate build directories for use with gn.') - parser.add_argument( - 'root', - default=default_root, - nargs='?', - help='root directory where to generate multiple out configurations') - parser.add_argument('--import', - action='append', - dest='import_rules', - default=[], - help='path to file defining default gn variables') - parser.add_argument('--gn-path', - default=None, - help='path to gn binary (default: look up in $PATH)') - parser.add_argument( - '--build-dir', - default='out', - help='path where the build should be created (default: %(default)s)') - args = parser.parse_args(args) - - # Load configuration (first global and then any user overrides). - settings = ConfigParserWithStringInterpolation() - settings.read([ - os.path.splitext(__file__)[0] + '.config', - os.path.expanduser('~/.setup-gn'), - ]) - - # Add private sections corresponding to --import argument. - if args.import_rules: - settings.add_section('$imports$') - for i, import_rule in enumerate(args.import_rules): - if not import_rule.startswith('//'): - import_rule = '//%s' % os.path.relpath( - os.path.abspath(import_rule), os.path.abspath(args.root)) - settings.set('$imports$', '$rule%d$' % i, import_rule) - - # Validate settings. - if settings.getstring('build', 'arch') not in ('64-bit', '32-bit', 'fat'): - sys.stderr.write('ERROR: invalid value for build.arch: %s\n' % - settings.getstring('build', 'arch')) - sys.exit(1) - - # Find path to gn binary either from command-line or in PATH. - if args.gn_path: - gn_path = args.gn_path - else: - gn_path = FindGn() - if gn_path is None: - sys.stderr.write('ERROR: cannot find gn in PATH\n') - sys.exit(1) - out_dir = os.path.join(args.root, args.build_dir) - if not os.path.isdir(out_dir): - os.makedirs(out_dir) - - GenerateXcodeProject(gn_path, args.root, out_dir, settings) - GenerateGnBuildRules(gn_path, args.root, out_dir, settings) +def Main(args): + default_root = os.path.normpath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)) + + parser = argparse.ArgumentParser( + description='Generate build directories for use with gn.') + parser.add_argument( + 'root', default=default_root, nargs='?', + help='root directory where to generate multiple out configurations') + parser.add_argument( + '--import', action='append', dest='import_rules', default=[], + help='path to file defining default gn variables') + parser.add_argument( + '--gn-path', default=None, + help='path to gn binary (default: look up in $PATH)') + parser.add_argument( + '--build-dir', default='out', + help='path where the build should be created (default: %(default)s)') + parser.add_argument( + '--config-path', default=os.path.expanduser('~/.setup-gn'), + help='path to the user config file (default: %(default)s)') + parser.add_argument( + '--system-config-path', default=os.path.splitext(__file__)[0] + '.config', + help='path to the default config file (default: %(default)s)') + parser.add_argument( + '--project-name', default='all', dest='proj_name', + help='name of the generated Xcode project (default: %(default)s)') + parser.add_argument( + '--no-xcode-project', action='store_true', default=False, + help='do not generate the build directory with XCode project') + args = parser.parse_args(args) + + # Load configuration (first global and then any user overrides). + settings = ConfigParserWithStringInterpolation() + settings.read([ + args.system_config_path, + args.config_path, + ]) + + # Add private sections corresponding to --import argument. + if args.import_rules: + settings.add_section('$imports$') + for i, import_rule in enumerate(args.import_rules): + if not import_rule.startswith('//'): + import_rule = '//%s' % os.path.relpath( + os.path.abspath(import_rule), os.path.abspath(args.root)) + settings.set('$imports$', '$rule%d$' % i, import_rule) + + # Validate settings. + if settings.getstring('build', 'arch') not in ('64-bit', '32-bit', 'fat'): + sys.stderr.write('ERROR: invalid value for build.arch: %s\n' % + settings.getstring('build', 'arch')) + sys.exit(1) + + # Find path to gn binary either from command-line or in PATH. + if args.gn_path: + gn_path = args.gn_path + else: + gn_path = FindGn() + if gn_path is None: + sys.stderr.write('ERROR: cannot find gn in PATH\n') + sys.exit(1) + + out_dir = os.path.join(args.root, args.build_dir) + if not os.path.isdir(out_dir): + os.makedirs(out_dir) + + if not args.no_xcode_project: + GenerateXcodeProject(gn_path, args.root, args.proj_name, out_dir, settings) + CreateLLDBInitFile(args.root, out_dir, settings) + GenerateGnBuildRules(gn_path, args.root, out_dir, settings) if __name__ == '__main__': - sys.exit(Main(sys.argv[1:])) + sys.exit(Main(sys.argv[1:])) diff --git a/build/ios/xcodescheme-testable.template b/build/ios/xcodescheme-testable.template new file mode 100644 index 0000000000..61b6f471b7 --- /dev/null +++ b/build/ios/xcodescheme-testable.template @@ -0,0 +1,10 @@ + + + + diff --git a/build/ios/xcodescheme.template b/build/ios/xcodescheme.template new file mode 100644 index 0000000000..514bea4ef0 --- /dev/null +++ b/build/ios/xcodescheme.template @@ -0,0 +1,80 @@ + + + + + + + + + + + + @{TESTABLES} + + + + + + + + + + + + + + + + + + + diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm index 397646c8f4..503d2febf3 100644 --- a/test/ios/host/cptest_application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -104,6 +104,17 @@ OperationStatus GetPendingReports(std::vector* pending_reports) { return process_snapshot; } +UIWindow* GetAnyWindow() { +#if defined(__IPHONE_15_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0 + if (@available(iOS 15.0, *)) { + UIWindowScene* scene = reinterpret_cast( + [UIApplication sharedApplication].connectedScenes.anyObject); + return scene.keyWindow; + } +#endif + return [UIApplication sharedApplication].windows[0]; +} + [[clang::optnone]] void recurse(int counter) { // Fill up the stack faster. int arr[1024]; @@ -355,7 +366,7 @@ - (void)crashCoreAutoLayoutSinkhole { // crash, so dispatch this out of the sinkhole. dispatch_async(dispatch_get_main_queue(), ^{ UIView* unattachedView = [[UIView alloc] init]; - UIWindow* window = [UIApplication sharedApplication].windows[0]; + UIWindow* window = GetAnyWindow(); [NSLayoutConstraint activateConstraints:@[ [window.rootViewController.view.bottomAnchor constraintEqualToAnchor:unattachedView.bottomAnchor], From c8c30a602e0eb2c22d6eb104067c8fdb7e0557e3 Mon Sep 17 00:00:00 2001 From: Walter Brebels Date: Thu, 7 Apr 2022 13:43:46 +0200 Subject: [PATCH 143/478] Find python3 or python2 --- util/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 2b42bd9f51..5ae9b3521a 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -376,7 +376,7 @@ if(APPLE) list(APPEND input_files "${full_path}") endforeach() - find_package(PythonInterp 2.7 REQUIRED) + find_package(Python COMPONENTS Interpreter REQUIRED) set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/util/mach") file(MAKE_DIRECTORY "${output_dir}") @@ -428,7 +428,7 @@ if(APPLE) OUTPUT ${output_files} COMMAND - "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" ${archs} ${sdk} ${includes} "${input}" ${output_files} + "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" ${archs} ${sdk} ${includes} "${input}" ${output_files} DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/mach/mig.py" "${input}" ) From 7bc7e7508fa42dff1d047dde13ec489d1df47b5b Mon Sep 17 00:00:00 2001 From: Sylvain Defresne Date: Fri, 8 Apr 2022 16:41:04 +0200 Subject: [PATCH 144/478] Fix flaky noop build failure of crashpad Linking crashpad (//third_party/crashpad/crashpad:util) target into a target built for a secondary toolchain could cause noop build failure because of an incorrect `include_dirs` directive. The library depends on a generated buildflag, which when in a secondary toolchain is generated to $root_gen_dir, a directory that includes the toolchain name (except for the primary one). The target added $root_build_dir/gen to its `include_dirs` which is equal to $root_gen_dir for the primary toolchain, but distinct for secondary toolchain. Moreover, `include_dirs` define directly in a `source_set` are placed before any `include_dirs` values inherited from configs. This means that $root_build_dir/gen was before $root_gen_dir in the list ($root_gen_dir is inherited from default config when building Chromium). The result is that building any crashpad files would result in them trying to first include the version of the buildflag that was generated for the primary toolchain, and if not found, using the correct one. This was then recorded in the depfile generated by the compiler. This meant that it was possible for the build to be incorrect (as the content of the buildflag may be different between the two toolchains) and cause flaky noop failures (as the buildlag generation for the primary toolchain and the compilation of the source file for the secondary toolchain are unordered, but a dependency was recorded via the depfile leading ninja to report a dirty build). The fix is simple, use the correct value $root_gen_dir in the `include_dirs` directive. Fixed: chromium:1314711 Change-Id: Icba521313e4105713e66fa576d730b00c7e74c21 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3579401 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- util/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 435d035731..c372ff49b3 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -581,7 +581,7 @@ crashpad_static_library("util") { ] if (crashpad_is_mac || crashpad_is_ios) { - include_dirs += [ "$root_build_dir/gen" ] + include_dirs += [ "$root_gen_dir" ] deps += [ ":mig_output" ] } From e180670cb5e70cde053585e4dd23a8fd5c7d5e04 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 8 Apr 2022 10:53:46 -0700 Subject: [PATCH 145/478] Add libcurl to required packages in documentation Follows up on discussion in: https://groups.google.com/a/chromium.org/g/crashpad-dev/c/1-QgplOJnw8 Change-Id: Ibb6bfca0455f34f23b6d833c4b67fd392eee74ca Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3579505 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- doc/developing.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/developing.md b/doc/developing.md index 60c4155360..a4017fb787 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -46,8 +46,9 @@ the `$PATH` environment variable: Windows](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/). * On Linux, obtain appropriate tools for C++ development through any appropriate means including the system’s package manager. On Debian and - Debian-based distributions, the `build-essential` and `zlib1g-dev` - packages should suffice. + Debian-based distributions, the `build-essential`, `zlib1g-dev`, and any + one of the `libcurl4-*-dev` packages such as `libcurl4-openssl-dev` should + suffice. * Chromium’s [depot_tools](https://www.chromium.org/developers/how-tos/depottools). * [Git](https://git-scm.com/). This is provided by Xcode on macOS, by From f882d2af82f38a8cc799575c545b3962e2ce6cf0 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 8 Apr 2022 12:41:12 -0700 Subject: [PATCH 146/478] Add root_gen_dir to crashpad_config Follows up on discussion in: https://groups.google.com/a/chromium.org/g/crashpad-dev/c/1-QgplOJnw8 Change-Id: I6def168182f5d3219db4691d4b81ea508fd08a85 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3577803 Reviewed-by: Mark Mentovai Commit-Queue: Joshua Peraza --- BUILD.gn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD.gn b/BUILD.gn index c0f8bcbc0d..61546be124 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -17,7 +17,10 @@ import("build/test.gni") import("util/net/tls.gni") config("crashpad_config") { - include_dirs = [ "." ] + include_dirs = [ + ".", + root_gen_dir, + ] } if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { From 646bba733b2339b0fa5f3ae0de659a11fb00bbf9 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 7 Apr 2022 19:52:07 -0400 Subject: [PATCH 147/478] ios: Add ScopedBackgroundTask to more flock file access. Use ScopedBackgroundTask to prevent file lock termination from happening when holding locked files in a shared AppGroup. Bug: 1313555 Change-Id: Idc0105f8ecdb65c26214a7265a216b9d480ed01d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3573184 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/crash_report_database_mac.mm | 8 ++++++++ client/settings.cc | 31 ++++++++++++++++++++++++++++- client/settings.h | 23 ++++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index c24b4a5dee..e72838a035 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -43,6 +43,10 @@ #include "util/misc/initialization_state_dcheck.h" #include "util/misc/metrics.h" +#if BUILDFLAG(IS_IOS) +#include "util/ios/scoped_background_task.h" +#endif // BUILDFLAG(IS_IOS) + namespace crashpad { namespace { @@ -182,6 +186,10 @@ OperationStatus RecordUploadAttempt(UploadReport* report, //! \brief Stores the flock of the file for the duration of //! GetReportForUploading() and RecordUploadAttempt(). base::ScopedFD lock_fd; +#if BUILDFLAG(IS_IOS) + //! \brief Obtain a background task assertion while a flock is in use. + internal::ScopedBackgroundTask ios_background_task{"UploadReportMac"}; +#endif // BUILDFLAG(IS_IOS) }; //! \brief Locates a crash report in the database by UUID. diff --git a/client/settings.cc b/client/settings.cc index 966481d628..8fe578f92f 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -71,6 +71,30 @@ void Settings::ScopedLockedFileHandle::Destroy() { #else // BUILDFLAG(IS_FUCHSIA) +#if BUILDFLAG(IS_IOS) + +Settings::ScopedLockedFileHandle::ScopedLockedFileHandle( + const FileHandle& value) + : ScopedGeneric(value) { + ios_background_task_ = std::make_unique( + "ScopedLockedFileHandle"); +} + +Settings::ScopedLockedFileHandle::ScopedLockedFileHandle( + Settings::ScopedLockedFileHandle&& rvalue) { + ios_background_task_.reset(rvalue.ios_background_task_.release()); + reset(rvalue.release()); +} + +Settings::ScopedLockedFileHandle& Settings::ScopedLockedFileHandle::operator=( + Settings::ScopedLockedFileHandle&& rvalue) { + ios_background_task_.reset(rvalue.ios_background_task_.release()); + reset(rvalue.release()); + return *this; +} + +#endif // BUILDFLAG(IS_IOS) + namespace internal { // static @@ -207,6 +231,10 @@ Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle( } return ScopedLockedFileHandle(scoped.release(), base::FilePath()); #else + // It's important to create the ScopedLockedFileHandle before calling + // LoggingLockFile on iOS, so a ScopedBackgroundTask is created *before* + // the LoggingLockFile call below. + ScopedLockedFileHandle handle(kInvalidFileHandle); if (scoped.is_valid()) { if (LoggingLockFile( scoped.get(), locking, FileLockingBlocking::kBlocking) != @@ -214,7 +242,8 @@ Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle( scoped.reset(); } } - return ScopedLockedFileHandle(scoped.release()); + handle.reset(scoped.release()); + return handle; #endif } diff --git a/client/settings.h b/client/settings.h index e476c60c3b..aedf30cd87 100644 --- a/client/settings.h +++ b/client/settings.h @@ -24,6 +24,10 @@ #include "util/misc/initialization_state.h" #include "util/misc/uuid.h" +#if BUILDFLAG(IS_IOS) +#include "util/ios/scoped_background_task.h" +#endif // BUILDFLAG(IS_IOS) + namespace crashpad { namespace internal { @@ -153,7 +157,24 @@ class Settings { FileHandle handle_; base::FilePath lockfile_path_; }; -#else // BUILDFLAG(IS_FUCHSIA) +#elif BUILDFLAG(IS_IOS) + // iOS needs to use ScopedBackgroundTask anytime a file lock is used. + class ScopedLockedFileHandle + : public base::ScopedGeneric { + public: + using base::ScopedGeneric< + FileHandle, + internal::ScopedLockedFileHandleTraits>::ScopedGeneric; + + ScopedLockedFileHandle(const FileHandle& value); + ScopedLockedFileHandle(ScopedLockedFileHandle&& rvalue); + ScopedLockedFileHandle& operator=(ScopedLockedFileHandle&& rvalue); + + private: + std::unique_ptr ios_background_task_; + }; +#else using ScopedLockedFileHandle = base::ScopedGeneric; #endif // BUILDFLAG(IS_FUCHSIA) From 12b09609eb8681b8344c7193740b4772b3f932fd Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 12 Apr 2022 11:26:16 +0200 Subject: [PATCH 148/478] fix: Make sure to free global Lock on shutdown (#61) --- client/crashpad_client_win.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 57696054de..6934831af0 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -69,7 +69,18 @@ HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; CrashpadClient::FirstChanceHandlerWin first_chance_handler_ = nullptr; // Guards multiple simultaneous calls to DumpWithoutCrash(). This is leaked. -base::Lock* g_non_crash_dump_lock; +base::Lock* g_non_crash_dump_lock = nullptr; + +class CrashDumpAutoReleaser { + public: + ~CrashDumpAutoReleaser() { + if (g_non_crash_dump_lock) { + delete g_non_crash_dump_lock; + g_non_crash_dump_lock = nullptr; + } + } +}; +static CrashDumpAutoReleaser gAutoReleaser; // Where we store a pointer to the context information when taking a non-crash // dump. @@ -394,8 +405,7 @@ bool StartHandlerProcess( } for (const base::FilePath& attachment : data->attachments) { AppendCommandLineArgument( - FormatArgumentString("attachment", attachment.value()), - &command_line); + FormatArgumentString("attachment", attachment.value()), &command_line); } ScopedKernelHANDLE this_process( From 412e849b4f1d8bc26165ce289b2a72da88609ec6 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 12 Apr 2022 11:47:25 +0200 Subject: [PATCH 149/478] Sync submodules and build files --- third_party/lss/lss | 2 +- third_party/mini_chromium/CMakeLists.txt | 1 - third_party/mini_chromium/mini_chromium | 2 +- util/CMakeLists.txt | 3 +++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/third_party/lss/lss b/third_party/lss/lss index 7bde79cc27..e1e7b0ad8e 160000 --- a/third_party/lss/lss +++ b/third_party/lss/lss @@ -1 +1 @@ -Subproject commit 7bde79cc274d06451bf65ae82c012a5d3e476b5a +Subproject commit e1e7b0ad8ee99a875b272c8e33e308472e897660 diff --git a/third_party/mini_chromium/CMakeLists.txt b/third_party/mini_chromium/CMakeLists.txt index 342b7aa3d9..4577c1d125 100644 --- a/third_party/mini_chromium/CMakeLists.txt +++ b/third_party/mini_chromium/CMakeLists.txt @@ -24,7 +24,6 @@ mc_append_sources( files/scoped_file.cc files/scoped_file.h format_macros.h - ignore_result.h logging.cc logging.h memory/free_deleter.h diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 0e22eed71e..5654edb422 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 0e22eed71eec97dacbe80822a14c5cd0b580d793 +Subproject commit 5654edb4225bcad13901155c819febb5748e502b diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 5ae9b3521a..e21bbcb099 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -221,6 +221,8 @@ if(APPLE) ios/ios_system_data_collector.mm ios/raw_logging.cc ios/raw_logging.h + ios/scoped_background_task.h + ios/scoped_background_task.mm ios/scoped_vm_read.cc ios/scoped_vm_read.h ) @@ -303,6 +305,7 @@ if(WIN32) win/context_wrappers.h win/critical_section_with_debug_info.cc win/critical_section_with_debug_info.h + win/exception_codes.h win/exception_handler_server.cc win/exception_handler_server.h win/get_function.cc From ed59c4260f5771c55118ae45589db7452732cf12 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 12 Apr 2022 12:23:25 +0200 Subject: [PATCH 150/478] Raise C++ std to C++17, and fix chromeos build flags --- CMakeLists.txt | 2 +- third_party/mini_chromium/build/chromeos_buildflags.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e228933505..b13b78faea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ else() enable_language(ASM) endif() -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(crashpad_interface INTERFACE) diff --git a/third_party/mini_chromium/build/chromeos_buildflags.h b/third_party/mini_chromium/build/chromeos_buildflags.h index c54f076845..72714a24ac 100644 --- a/third_party/mini_chromium/build/chromeos_buildflags.h +++ b/third_party/mini_chromium/build/chromeos_buildflags.h @@ -7,7 +7,7 @@ #include "build/buildflag.h" -#define BUILDFLAG_INTERNAL_IS_CHROMEOS_LACROS() (0) -#define BUILDFLAG_INTERNAL_IS_CHROMEOS_ASH() (0) +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_CHROMEOS_LACROS() (0) +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_CHROMEOS_ASH() (0) #endif // MINI_CHROMIUM_BUILD_CHROMEOS_BUILDFLAGS_H_ From c372875a79a189d8856dc255c339f4b890b83b00 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 12 Apr 2022 12:38:16 +0200 Subject: [PATCH 151/478] Enable ARC for the iOS build --- util/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index e21bbcb099..e37bfb155e 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -225,7 +225,15 @@ if(APPLE) ios/scoped_background_task.mm ios/scoped_vm_read.cc ios/scoped_vm_read.h - ) + ) + # This specific file requires ARC support, while other parts do not + # build when ARC is enabled. + set_source_files_properties( + ios/scoped_background_task.mm + PROPERTIES + COMPILE_FLAGS + "-fobjc-arc" + ) endif() endif() From 68aba08c48bb428b7b159b3371163f86e8d5a126 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 11 Apr 2022 19:38:51 -0400 Subject: [PATCH 152/478] ios: Don't block main thread on suspend. Because the upload thread uses synchronous upload, calling Stop() on that thread from the main thread will lock, and trigger a terminate when transitioning from foreground to background. Additionally, background assertions now only last 30 seconds, so shorten the timeout to 20 seconds. This is a followup to https://crrev.com/c/3517967. Bug: crashpad:1315441 Change-Id: Ic6886607805667ffce5ecf41716fc63333a341b8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3577820 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/ios_handler/in_process_handler.cc | 8 ++++++-- handler/crash_report_upload_thread.cc | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index abde07f609..69923210aa 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -111,8 +111,12 @@ bool InProcessHandler::Initialize( prune_thread_->Start(); if (!is_app_extension) { - system_data_.SetActiveApplicationCallback( - [this](bool active) { UpdatePruneAndUploadThreads(active); }); + system_data_.SetActiveApplicationCallback([this](bool active) { + dispatch_async( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UpdatePruneAndUploadThreads(active); + }); + }); } base::FilePath cached_writer_path = NewLockedFilePath(); diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index efbeab7804..138cf80026 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -311,7 +311,13 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport( } http_transport->SetBodyStream(http_multipart_builder.GetBodyStream()); // TODO(mark): The timeout should be configurable by the client. - http_transport->SetTimeout(60.0); // 1 minute. +#if BUILDFLAG(IS_IOS) + // iOS background assertions only last 30 seconds, keep the timeout shorter. + double timeout_seconds = 20; +#else + double timeout_seconds = 60; +#endif + http_transport->SetTimeout(timeout_seconds); std::string url = url_; if (options_.identify_client_via_url) { From 36c88b15b7d872846966bba8bf4be623c3fb65c0 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Mon, 18 Apr 2022 11:25:38 -0700 Subject: [PATCH 153/478] Initializes contexts on ios x64 builds In a later CL, in some cases these structs were not zero-initialized which caused some iOS tests to fail. We now zero-initialize these structs which should be harmless now, and useful later. Bug: 1250098 Change-Id: I933e80e56714a1d8988deae3aa56ec36ed98ef03 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3538665 Reviewed-by: Justin Cohen Commit-Queue: Alex Gough --- client/ios_handler/exception_processor.mm | 2 +- snapshot/ios/exception_snapshot_ios_intermediate_dump.cc | 9 +++++++-- snapshot/ios/thread_snapshot_ios_intermediate_dump.cc | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/ios_handler/exception_processor.mm b/client/ios_handler/exception_processor.mm index 3211228c22..5aa4c78d53 100644 --- a/client/ios_handler/exception_processor.mm +++ b/client/ios_handler/exception_processor.mm @@ -294,7 +294,7 @@ static __attribute__((noinline)) id HANDLE_UNCAUGHT_NSEXCEPTION( SetNSExceptionAnnotations(exception, name, reason); LOG(WARNING) << "Handling Objective-C exception name: " << name << " reason: " << reason << " with sinkhole: " << sinkhole; - NativeCPUContext cpu_context; + NativeCPUContext cpu_context{}; CaptureContext(&cpu_context); ExceptionPreprocessorState* preprocessor_state = diff --git a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc index a45d4cc290..7530912a9d 100644 --- a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc @@ -66,6 +66,13 @@ using Key = IntermediateDumpKey; ExceptionSnapshotIOSIntermediateDump::ExceptionSnapshotIOSIntermediateDump() : ExceptionSnapshot(), +#if defined(ARCH_CPU_X86_64) + context_x86_64_(), +#elif defined(ARCH_CPU_ARM64) + context_arm64_(), +#else +#error Port to your CPU architecture +#endif context_(), codes_(), thread_id_(0), @@ -379,11 +386,9 @@ void ExceptionSnapshotIOSIntermediateDump:: } #if defined(ARCH_CPU_X86_64) - context_x86_64_ = {}; context_x86_64_.rip = frames[0]; // instruction pointer context_x86_64_.rsp = frames[1]; #elif defined(ARCH_CPU_ARM64) - context_arm64_ = {}; context_arm64_.sp = 0; context_arm64_.pc = frames[0]; context_arm64_.regs[30] = frames[1]; // link register diff --git a/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc b/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc index b7ede298ed..ed7b28aa49 100644 --- a/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc @@ -68,6 +68,11 @@ using Key = IntermediateDumpKey; ThreadSnapshotIOSIntermediateDump::ThreadSnapshotIOSIntermediateDump() : ThreadSnapshot(), +#if defined(ARCH_CPU_X86_64) + context_x86_64_(), +#elif defined(ARCH_CPU_ARM64) + context_arm64_(), +#endif context_(), stack_(), thread_id_(0), From 8647761c7d2832e2488fe62e2b80ca6fe249fd6b Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 18 Apr 2022 13:59:02 -0400 Subject: [PATCH 154/478] ios: Ensure ScopedLockedFileHandle and UploadReportMac destructor order. Followup to crrev.com/c/3573184, which did not honor destructor order, leading to the background task releasing before the lock. Bug: 1313555 Change-Id: Ifbd3902964552458b83cfc550f50058067021499 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3591012 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/crash_report_database_mac.mm | 7 ++++--- client/settings.cc | 5 +++++ client/settings.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index e72838a035..c6abe8aaa6 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -183,13 +183,14 @@ OperationStatus RecordUploadAttempt(UploadReport* report, //! \brief A private extension of the Report class that maintains bookkeeping //! information of the database. struct UploadReportMac : public UploadReport { - //! \brief Stores the flock of the file for the duration of - //! GetReportForUploading() and RecordUploadAttempt(). - base::ScopedFD lock_fd; #if BUILDFLAG(IS_IOS) //! \brief Obtain a background task assertion while a flock is in use. + //! Ensure this is defined first so it is destroyed last. internal::ScopedBackgroundTask ios_background_task{"UploadReportMac"}; #endif // BUILDFLAG(IS_IOS) + //! \brief Stores the flock of the file for the duration of + //! GetReportForUploading() and RecordUploadAttempt(). + base::ScopedFD lock_fd; }; //! \brief Locates a crash report in the database by UUID. diff --git a/client/settings.cc b/client/settings.cc index 8fe578f92f..eef24f7149 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -93,6 +93,11 @@ Settings::ScopedLockedFileHandle& Settings::ScopedLockedFileHandle::operator=( return *this; } +Settings::ScopedLockedFileHandle::~ScopedLockedFileHandle() { + // Call reset() to ensure the lock is released before the ios_background_task. + reset(); +} + #endif // BUILDFLAG(IS_IOS) namespace internal { diff --git a/client/settings.h b/client/settings.h index aedf30cd87..8ad8a2b16f 100644 --- a/client/settings.h +++ b/client/settings.h @@ -171,6 +171,8 @@ class Settings { ScopedLockedFileHandle(ScopedLockedFileHandle&& rvalue); ScopedLockedFileHandle& operator=(ScopedLockedFileHandle&& rvalue); + ~ScopedLockedFileHandle(); + private: std::unique_ptr ios_background_task_; }; From 12cb55fecfc6bbb3cb82929d1a9ddaf118714b42 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 18 Apr 2022 14:28:19 -0400 Subject: [PATCH 155/478] ios: Safely handle database errors when saving crash reports. Bug: 1317298 Change-Id: Iac4050fc4ec61f391bab85c4d8ac97fd8e898f14 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3591013 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/ios_handler/in_process_handler.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index 69923210aa..f37b4d50cf 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -303,6 +303,7 @@ void InProcessHandler::SaveSnapshot( if (database_status != CrashReportDatabase::kNoError) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kPrepareNewCrashReportFailed); + return; } process_snapshot.SetReportID(new_report->ReportID()); @@ -317,6 +318,7 @@ void InProcessHandler::SaveSnapshot( if (!minidump.WriteEverything(new_report->Writer())) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kMinidumpWriteFailed); + return; } UUID uuid; database_status = @@ -324,6 +326,7 @@ void InProcessHandler::SaveSnapshot( if (database_status != CrashReportDatabase::kNoError) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return; } if (upload_thread_) { From 94ea6d6f3085b8b5555df55186d8338fd8169aec Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 20 Apr 2022 10:10:52 -0700 Subject: [PATCH 156/478] Remove ELF headers Bug: b/180059624 Change-Id: I9db01233114d223c2f90e26267622650c9115484 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3597630 Reviewed-by: Justin Cohen Commit-Queue: Joshua Peraza --- compat/non_elf/elf.h | 20 - third_party/glibc/BUILD.gn | 17 - third_party/glibc/COPYING.LIB | 502 ---- third_party/glibc/README.crashpad | 16 - third_party/glibc/elf/elf.h | 4003 ----------------------------- 5 files changed, 4558 deletions(-) delete mode 100644 compat/non_elf/elf.h delete mode 100644 third_party/glibc/BUILD.gn delete mode 100644 third_party/glibc/COPYING.LIB delete mode 100644 third_party/glibc/README.crashpad delete mode 100644 third_party/glibc/elf/elf.h diff --git a/compat/non_elf/elf.h b/compat/non_elf/elf.h deleted file mode 100644 index 1245f16dd8..0000000000 --- a/compat/non_elf/elf.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2019 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef CRASHPAD_COMPAT_NON_ELF_ELF_H_ -#define CRASHPAD_COMPAT_NON_ELF_ELF_H_ - -#include "third_party/glibc/elf/elf.h" - -#endif // CRASHPAD_COMPAT_NON_ELF_ELF_H_ diff --git a/third_party/glibc/BUILD.gn b/third_party/glibc/BUILD.gn deleted file mode 100644 index 3f2b08bc0d..0000000000 --- a/third_party/glibc/BUILD.gn +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2019 The Crashpad Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source_set("glibc") { - sources = [ "elf/elf.h" ] -} diff --git a/third_party/glibc/COPYING.LIB b/third_party/glibc/COPYING.LIB deleted file mode 100644 index 4362b49151..0000000000 --- a/third_party/glibc/COPYING.LIB +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/third_party/glibc/README.crashpad b/third_party/glibc/README.crashpad deleted file mode 100644 index b550ad98a7..0000000000 --- a/third_party/glibc/README.crashpad +++ /dev/null @@ -1,16 +0,0 @@ -Name: GNU C Library -Short Name: glibc -URL: https://www.gnu.org/software/libc/ -URL: https://sourceware.org/git/?p=glibc.git -Version: 2.29 -License: GNU LGPL 2.1 -License File: COPYING.LIB -Security Critical: no - -Description: -glibc is the GNU Project’s implementation of the C standard library. - -Local Modifications: - - Only elf/elf.h is included. Its #include of has been removed, - and it uses of __BEGIN_DECLS and __END_DECLS have been replaced with inline - versions in the manner that misc/sys/cdefs.h defines those macros. diff --git a/third_party/glibc/elf/elf.h b/third_party/glibc/elf/elf.h deleted file mode 100644 index 331536b497..0000000000 --- a/third_party/glibc/elf/elf.h +++ /dev/null @@ -1,4003 +0,0 @@ -/* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2019 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _ELF_H -#define _ELF_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Standard ELF types. */ - -#include - -/* Type for a 16-bit quantity. */ -typedef uint16_t Elf32_Half; -typedef uint16_t Elf64_Half; - -/* Types for signed and unsigned 32-bit quantities. */ -typedef uint32_t Elf32_Word; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; - -/* Types for signed and unsigned 64-bit quantities. */ -typedef uint64_t Elf32_Xword; -typedef int64_t Elf32_Sxword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* Type of addresses. */ -typedef uint32_t Elf32_Addr; -typedef uint64_t Elf64_Addr; - -/* Type of file offsets. */ -typedef uint32_t Elf32_Off; -typedef uint64_t Elf64_Off; - -/* Type for section indices, which are 16-bit quantities. */ -typedef uint16_t Elf32_Section; -typedef uint16_t Elf64_Section; - -/* Type for version symbol information. */ -typedef Elf32_Half Elf32_Versym; -typedef Elf64_Half Elf64_Versym; - - -/* The ELF file header. This appears at the start of every ELF file. */ - -#define EI_NIDENT (16) - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf64_Half e_type; /* Object file type */ - Elf64_Half e_machine; /* Architecture */ - Elf64_Word e_version; /* Object file version */ - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; /* Processor-specific flags */ - Elf64_Half e_ehsize; /* ELF header size in bytes */ - Elf64_Half e_phentsize; /* Program header table entry size */ - Elf64_Half e_phnum; /* Program header table entry count */ - Elf64_Half e_shentsize; /* Section header table entry size */ - Elf64_Half e_shnum; /* Section header table entry count */ - Elf64_Half e_shstrndx; /* Section header string table index */ -} Elf64_Ehdr; - -/* Fields in the e_ident array. The EI_* macros are indices into the - array. The macros under each EI_* macro are the values the byte - may have. */ - -#define EI_MAG0 0 /* File identification byte 0 index */ -#define ELFMAG0 0x7f /* Magic number byte 0 */ - -#define EI_MAG1 1 /* File identification byte 1 index */ -#define ELFMAG1 'E' /* Magic number byte 1 */ - -#define EI_MAG2 2 /* File identification byte 2 index */ -#define ELFMAG2 'L' /* Magic number byte 2 */ - -#define EI_MAG3 3 /* File identification byte 3 index */ -#define ELFMAG3 'F' /* Magic number byte 3 */ - -/* Conglomeration of the identification bytes, for easy testing as a word. */ -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASSNONE 0 /* Invalid class */ -#define ELFCLASS32 1 /* 32-bit objects */ -#define ELFCLASS64 2 /* 64-bit objects */ -#define ELFCLASSNUM 3 - -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATANONE 0 /* Invalid data encoding */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ -#define ELFDATA2MSB 2 /* 2's complement, big endian */ -#define ELFDATANUM 3 - -#define EI_VERSION 6 /* File version byte index */ - /* Value must be EV_CURRENT */ - -#define EI_OSABI 7 /* OS ABI identification */ -#define ELFOSABI_NONE 0 /* UNIX System V ABI */ -#define ELFOSABI_SYSV 0 /* Alias. */ -#define ELFOSABI_HPUX 1 /* HP-UX */ -#define ELFOSABI_NETBSD 2 /* NetBSD. */ -#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ -#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ -#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ -#define ELFOSABI_AIX 7 /* IBM AIX. */ -#define ELFOSABI_IRIX 8 /* SGI Irix. */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ -#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ -#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -#define EI_ABIVERSION 8 /* ABI version */ - -#define EI_PAD 9 /* Byte index of padding bytes */ - -/* Legal values for e_type (object file type). */ - -#define ET_NONE 0 /* No file type */ -#define ET_REL 1 /* Relocatable file */ -#define ET_EXEC 2 /* Executable file */ -#define ET_DYN 3 /* Shared object file */ -#define ET_CORE 4 /* Core file */ -#define ET_NUM 5 /* Number of defined types */ -#define ET_LOOS 0xfe00 /* OS-specific range start */ -#define ET_HIOS 0xfeff /* OS-specific range end */ -#define ET_LOPROC 0xff00 /* Processor-specific range start */ -#define ET_HIPROC 0xffff /* Processor-specific range end */ - -/* Legal values for e_machine (architecture). */ - -#define EM_NONE 0 /* No machine */ -#define EM_M32 1 /* AT&T WE 32100 */ -#define EM_SPARC 2 /* SUN SPARC */ -#define EM_386 3 /* Intel 80386 */ -#define EM_68K 4 /* Motorola m68k family */ -#define EM_88K 5 /* Motorola m88k family */ -#define EM_IAMCU 6 /* Intel MCU */ -#define EM_860 7 /* Intel 80860 */ -#define EM_MIPS 8 /* MIPS R3000 big-endian */ -#define EM_S370 9 /* IBM System/370 */ -#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ - /* reserved 11-14 */ -#define EM_PARISC 15 /* HPPA */ - /* reserved 16 */ -#define EM_VPP500 17 /* Fujitsu VPP500 */ -#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ -#define EM_960 19 /* Intel 80960 */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC 64-bit */ -#define EM_S390 22 /* IBM S390 */ -#define EM_SPU 23 /* IBM SPU/SPC */ - /* reserved 24-35 */ -#define EM_V800 36 /* NEC V800 series */ -#define EM_FR20 37 /* Fujitsu FR20 */ -#define EM_RH32 38 /* TRW RH-32 */ -#define EM_RCE 39 /* Motorola RCE */ -#define EM_ARM 40 /* ARM */ -#define EM_FAKE_ALPHA 41 /* Digital Alpha */ -#define EM_SH 42 /* Hitachi SH */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit */ -#define EM_TRICORE 44 /* Siemens Tricore */ -#define EM_ARC 45 /* Argonaut RISC Core */ -#define EM_H8_300 46 /* Hitachi H8/300 */ -#define EM_H8_300H 47 /* Hitachi H8/300H */ -#define EM_H8S 48 /* Hitachi H8S */ -#define EM_H8_500 49 /* Hitachi H8/500 */ -#define EM_IA_64 50 /* Intel Merced */ -#define EM_MIPS_X 51 /* Stanford MIPS-X */ -#define EM_COLDFIRE 52 /* Motorola Coldfire */ -#define EM_68HC12 53 /* Motorola M68HC12 */ -#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator */ -#define EM_PCP 55 /* Siemens PCP */ -#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ -#define EM_NDR1 57 /* Denso NDR1 microprocessor */ -#define EM_STARCORE 58 /* Motorola Start*Core processor */ -#define EM_ME16 59 /* Toyota ME16 processor */ -#define EM_ST100 60 /* STMicroelectronic ST100 processor */ -#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam */ -#define EM_X86_64 62 /* AMD x86-64 architecture */ -#define EM_PDSP 63 /* Sony DSP Processor */ -#define EM_PDP10 64 /* Digital PDP-10 */ -#define EM_PDP11 65 /* Digital PDP-11 */ -#define EM_FX66 66 /* Siemens FX66 microcontroller */ -#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ -#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ -#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ -#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ -#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ -#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ -#define EM_SVX 73 /* Silicon Graphics SVx */ -#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ -#define EM_VAX 75 /* Digital VAX */ -#define EM_CRIS 76 /* Axis Communications 32-bit emb.proc */ -#define EM_JAVELIN 77 /* Infineon Technologies 32-bit emb.proc */ -#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ -#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ -#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc */ -#define EM_HUANY 81 /* Harvard University machine-independent object files */ -#define EM_PRISM 82 /* SiTera Prism */ -#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ -#define EM_FR30 84 /* Fujitsu FR30 */ -#define EM_D10V 85 /* Mitsubishi D10V */ -#define EM_D30V 86 /* Mitsubishi D30V */ -#define EM_V850 87 /* NEC v850 */ -#define EM_M32R 88 /* Mitsubishi M32R */ -#define EM_MN10300 89 /* Matsushita MN10300 */ -#define EM_MN10200 90 /* Matsushita MN10200 */ -#define EM_PJ 91 /* picoJava */ -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ -#define EM_ARC_COMPACT 93 /* ARC International ARCompact */ -#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ -#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore */ -#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose Proc */ -#define EM_NS32K 97 /* National Semi. 32000 */ -#define EM_TPC 98 /* Tenor Network TPC */ -#define EM_SNP1K 99 /* Trebia SNP 1000 */ -#define EM_ST200 100 /* STMicroelectronics ST200 */ -#define EM_IP2K 101 /* Ubicom IP2xxx */ -#define EM_MAX 102 /* MAX processor */ -#define EM_CR 103 /* National Semi. CompactRISC */ -#define EM_F2MC16 104 /* Fujitsu F2MC16 */ -#define EM_MSP430 105 /* Texas Instruments msp430 */ -#define EM_BLACKFIN 106 /* Analog Devices Blackfin DSP */ -#define EM_SE_C33 107 /* Seiko Epson S1C33 family */ -#define EM_SEP 108 /* Sharp embedded microprocessor */ -#define EM_ARCA 109 /* Arca RISC */ -#define EM_UNICORE 110 /* PKU-Unity & MPRC Peking Uni. mc series */ -#define EM_EXCESS 111 /* eXcess configurable cpu */ -#define EM_DXP 112 /* Icera Semi. Deep Execution Processor */ -#define EM_ALTERA_NIOS2 113 /* Altera Nios II */ -#define EM_CRX 114 /* National Semi. CompactRISC CRX */ -#define EM_XGATE 115 /* Motorola XGATE */ -#define EM_C166 116 /* Infineon C16x/XC16x */ -#define EM_M16C 117 /* Renesas M16C */ -#define EM_DSPIC30F 118 /* Microchip Technology dsPIC30F */ -#define EM_CE 119 /* Freescale Communication Engine RISC */ -#define EM_M32C 120 /* Renesas M32C */ - /* reserved 121-130 */ -#define EM_TSK3000 131 /* Altium TSK3000 */ -#define EM_RS08 132 /* Freescale RS08 */ -#define EM_SHARC 133 /* Analog Devices SHARC family */ -#define EM_ECOG2 134 /* Cyan Technology eCOG2 */ -#define EM_SCORE7 135 /* Sunplus S+core7 RISC */ -#define EM_DSP24 136 /* New Japan Radio (NJR) 24-bit DSP */ -#define EM_VIDEOCORE3 137 /* Broadcom VideoCore III */ -#define EM_LATTICEMICO32 138 /* RISC for Lattice FPGA */ -#define EM_SE_C17 139 /* Seiko Epson C17 */ -#define EM_TI_C6000 140 /* Texas Instruments TMS320C6000 DSP */ -#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP */ -#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP */ -#define EM_TI_ARP32 143 /* Texas Instruments App. Specific RISC */ -#define EM_TI_PRU 144 /* Texas Instruments Prog. Realtime Unit */ - /* reserved 145-159 */ -#define EM_MMDSP_PLUS 160 /* STMicroelectronics 64bit VLIW DSP */ -#define EM_CYPRESS_M8C 161 /* Cypress M8C */ -#define EM_R32C 162 /* Renesas R32C */ -#define EM_TRIMEDIA 163 /* NXP Semi. TriMedia */ -#define EM_QDSP6 164 /* QUALCOMM DSP6 */ -#define EM_8051 165 /* Intel 8051 and variants */ -#define EM_STXP7X 166 /* STMicroelectronics STxP7x */ -#define EM_NDS32 167 /* Andes Tech. compact code emb. RISC */ -#define EM_ECOG1X 168 /* Cyan Technology eCOG1X */ -#define EM_MAXQ30 169 /* Dallas Semi. MAXQ30 mc */ -#define EM_XIMO16 170 /* New Japan Radio (NJR) 16-bit DSP */ -#define EM_MANIK 171 /* M2000 Reconfigurable RISC */ -#define EM_CRAYNV2 172 /* Cray NV2 vector architecture */ -#define EM_RX 173 /* Renesas RX */ -#define EM_METAG 174 /* Imagination Tech. META */ -#define EM_MCST_ELBRUS 175 /* MCST Elbrus */ -#define EM_ECOG16 176 /* Cyan Technology eCOG16 */ -#define EM_CR16 177 /* National Semi. CompactRISC CR16 */ -#define EM_ETPU 178 /* Freescale Extended Time Processing Unit */ -#define EM_SLE9X 179 /* Infineon Tech. SLE9X */ -#define EM_L10M 180 /* Intel L10M */ -#define EM_K10M 181 /* Intel K10M */ - /* reserved 182 */ -#define EM_AARCH64 183 /* ARM AARCH64 */ - /* reserved 184 */ -#define EM_AVR32 185 /* Amtel 32-bit microprocessor */ -#define EM_STM8 186 /* STMicroelectronics STM8 */ -#define EM_TILE64 187 /* Tileta TILE64 */ -#define EM_TILEPRO 188 /* Tilera TILEPro */ -#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ -#define EM_CUDA 190 /* NVIDIA CUDA */ -#define EM_TILEGX 191 /* Tilera TILE-Gx */ -#define EM_CLOUDSHIELD 192 /* CloudShield */ -#define EM_COREA_1ST 193 /* KIPO-KAIST Core-A 1st gen. */ -#define EM_COREA_2ND 194 /* KIPO-KAIST Core-A 2nd gen. */ -#define EM_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */ -#define EM_OPEN8 196 /* Open8 RISC */ -#define EM_RL78 197 /* Renesas RL78 */ -#define EM_VIDEOCORE5 198 /* Broadcom VideoCore V */ -#define EM_78KOR 199 /* Renesas 78KOR */ -#define EM_56800EX 200 /* Freescale 56800EX DSC */ -#define EM_BA1 201 /* Beyond BA1 */ -#define EM_BA2 202 /* Beyond BA2 */ -#define EM_XCORE 203 /* XMOS xCORE */ -#define EM_MCHP_PIC 204 /* Microchip 8-bit PIC(r) */ - /* reserved 205-209 */ -#define EM_KM32 210 /* KM211 KM32 */ -#define EM_KMX32 211 /* KM211 KMX32 */ -#define EM_EMX16 212 /* KM211 KMX16 */ -#define EM_EMX8 213 /* KM211 KMX8 */ -#define EM_KVARC 214 /* KM211 KVARC */ -#define EM_CDP 215 /* Paneve CDP */ -#define EM_COGE 216 /* Cognitive Smart Memory Processor */ -#define EM_COOL 217 /* Bluechip CoolEngine */ -#define EM_NORC 218 /* Nanoradio Optimized RISC */ -#define EM_CSR_KALIMBA 219 /* CSR Kalimba */ -#define EM_Z80 220 /* Zilog Z80 */ -#define EM_VISIUM 221 /* Controls and Data Services VISIUMcore */ -#define EM_FT32 222 /* FTDI Chip FT32 */ -#define EM_MOXIE 223 /* Moxie processor */ -#define EM_AMDGPU 224 /* AMD GPU */ - /* reserved 225-242 */ -#define EM_RISCV 243 /* RISC-V */ - -#define EM_BPF 247 /* Linux BPF -- in-kernel virtual machine */ -#define EM_CSKY 252 /* C_SKY */ - -#define EM_NUM 253 - -/* Old spellings/synonyms. */ - -#define EM_ARC_A5 EM_ARC_COMPACT - -/* If it is necessary to assign new unofficial EM_* values, please - pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the - chances of collision with official or non-GNU unofficial values. */ - -#define EM_ALPHA 0x9026 - -/* Legal values for e_version (version). */ - -#define EV_NONE 0 /* Invalid ELF version */ -#define EV_CURRENT 1 /* Current version */ -#define EV_NUM 2 - -/* Section header. */ - -typedef struct -{ - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -typedef struct -{ - Elf64_Word sh_name; /* Section name (string tbl index) */ - Elf64_Word sh_type; /* Section type */ - Elf64_Xword sh_flags; /* Section flags */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Section size in bytes */ - Elf64_Word sh_link; /* Link to another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -/* Special section indices. */ - -#define SHN_UNDEF 0 /* Undefined section */ -#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ -#define SHN_LOPROC 0xff00 /* Start of processor-specific */ -#define SHN_BEFORE 0xff00 /* Order section before all others - (Solaris). */ -#define SHN_AFTER 0xff01 /* Order section after all others - (Solaris). */ -#define SHN_HIPROC 0xff1f /* End of processor-specific */ -#define SHN_LOOS 0xff20 /* Start of OS-specific */ -#define SHN_HIOS 0xff3f /* End of OS-specific */ -#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ -#define SHN_COMMON 0xfff2 /* Associated symbol is common */ -#define SHN_XINDEX 0xffff /* Index is in extra table. */ -#define SHN_HIRESERVE 0xffff /* End of reserved indices */ - -/* Legal values for sh_type (section type). */ - -#define SHT_NULL 0 /* Section header table entry unused */ -#define SHT_PROGBITS 1 /* Program data */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addends */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Dynamic linking information */ -#define SHT_NOTE 7 /* Notes */ -#define SHT_NOBITS 8 /* Program space with no data (bss) */ -#define SHT_REL 9 /* Relocation entries, no addends */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ -#define SHT_INIT_ARRAY 14 /* Array of constructors */ -#define SHT_FINI_ARRAY 15 /* Array of destructors */ -#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ -#define SHT_GROUP 17 /* Section group */ -#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ -#define SHT_NUM 19 /* Number of defined types. */ -#define SHT_LOOS 0x60000000 /* Start OS-specific. */ -#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ -#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ -#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ -#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ -#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ -#define SHT_SUNW_move 0x6ffffffa -#define SHT_SUNW_COMDAT 0x6ffffffb -#define SHT_SUNW_syminfo 0x6ffffffc -#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ -#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ -#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ -#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ -#define SHT_HIOS 0x6fffffff /* End OS-specific type */ -#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ -#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ -#define SHT_LOUSER 0x80000000 /* Start of application-specific */ -#define SHT_HIUSER 0x8fffffff /* End of application-specific */ - -/* Legal values for sh_flags (section flags). */ - -#define SHF_WRITE (1 << 0) /* Writable */ -#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ -#define SHF_EXECINSTR (1 << 2) /* Executable */ -#define SHF_MERGE (1 << 4) /* Might be merged */ -#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ -#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ -#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ -#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling - required */ -#define SHF_GROUP (1 << 9) /* Section is member of a group. */ -#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ -#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ -#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ -#define SHF_ORDERED (1 << 30) /* Special ordering requirement - (Solaris). */ -#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless - referenced or allocated (Solaris).*/ - -/* Section compression header. Used when SHF_COMPRESSED is set. */ - -typedef struct -{ - Elf32_Word ch_type; /* Compression format. */ - Elf32_Word ch_size; /* Uncompressed data size. */ - Elf32_Word ch_addralign; /* Uncompressed data alignment. */ -} Elf32_Chdr; - -typedef struct -{ - Elf64_Word ch_type; /* Compression format. */ - Elf64_Word ch_reserved; - Elf64_Xword ch_size; /* Uncompressed data size. */ - Elf64_Xword ch_addralign; /* Uncompressed data alignment. */ -} Elf64_Chdr; - -/* Legal values for ch_type (compression algorithm). */ -#define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */ -#define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */ -#define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */ -#define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */ -#define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */ - -/* Section group handling. */ -#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ - -/* Symbol table entry. */ - -typedef struct -{ - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ -} Elf32_Sym; - -typedef struct -{ - Elf64_Word st_name; /* Symbol name (string tbl index) */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf64_Section st_shndx; /* Section index */ - Elf64_Addr st_value; /* Symbol value */ - Elf64_Xword st_size; /* Symbol size */ -} Elf64_Sym; - -/* The syminfo section if available contains additional information about - every dynamic symbol. */ - -typedef struct -{ - Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf32_Half si_flags; /* Per symbol flags */ -} Elf32_Syminfo; - -typedef struct -{ - Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ - Elf64_Half si_flags; /* Per symbol flags */ -} Elf64_Syminfo; - -/* Possible values for si_boundto. */ -#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ -#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ -#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ - -/* Possible bitmasks for si_flags. */ -#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ -#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ -#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ -#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy - loaded */ -/* Syminfo version values. */ -#define SYMINFO_NONE 0 -#define SYMINFO_CURRENT 1 -#define SYMINFO_NUM 2 - - -/* How to extract and insert information held in the st_info field. */ - -#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) -#define ELF32_ST_TYPE(val) ((val) & 0xf) -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ -#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) -#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) -#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) - -/* Legal values for ST_BIND subfield of st_info (symbol binding). */ - -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* Weak symbol */ -#define STB_NUM 3 /* Number of defined types. */ -#define STB_LOOS 10 /* Start of OS-specific */ -#define STB_GNU_UNIQUE 10 /* Unique symbol. */ -#define STB_HIOS 12 /* End of OS-specific */ -#define STB_LOPROC 13 /* Start of processor-specific */ -#define STB_HIPROC 15 /* End of processor-specific */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_NOTYPE 0 /* Symbol type is unspecified */ -#define STT_OBJECT 1 /* Symbol is a data object */ -#define STT_FUNC 2 /* Symbol is a code object */ -#define STT_SECTION 3 /* Symbol associated with a section */ -#define STT_FILE 4 /* Symbol's name is file name */ -#define STT_COMMON 5 /* Symbol is a common data object */ -#define STT_TLS 6 /* Symbol is thread-local data object*/ -#define STT_NUM 7 /* Number of defined types. */ -#define STT_LOOS 10 /* Start of OS-specific */ -#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ -#define STT_HIOS 12 /* End of OS-specific */ -#define STT_LOPROC 13 /* Start of processor-specific */ -#define STT_HIPROC 15 /* End of processor-specific */ - - -/* Symbol table indices are found in the hash buckets and chain table - of a symbol hash table section. This special index value indicates - the end of a chain, meaning no further symbols are found in that bucket. */ - -#define STN_UNDEF 0 /* End of a chain. */ - - -/* How to extract and insert information held in the st_other field. */ - -#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) - -/* For ELF64 the definitions are the same. */ -#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) - -/* Symbol visibility specification encoded in the st_other field. */ -#define STV_DEFAULT 0 /* Default symbol visibility rules */ -#define STV_INTERNAL 1 /* Processor specific hidden class */ -#define STV_HIDDEN 2 /* Sym unavailable in other modules */ -#define STV_PROTECTED 3 /* Not preemptible, not exported */ - - -/* Relocation table entry without addend (in section of type SHT_REL). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ -} Elf32_Rel; - -/* I have seen two different definitions of the Elf64_Rel and - Elf64_Rela structures, so we'll leave them out until Novell (or - whoever) gets their act together. */ -/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ -} Elf64_Rel; - -/* Relocation table entry with addend (in section of type SHT_RELA). */ - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ - Elf32_Sword r_addend; /* Addend */ -} Elf32_Rela; - -typedef struct -{ - Elf64_Addr r_offset; /* Address */ - Elf64_Xword r_info; /* Relocation type and symbol index */ - Elf64_Sxword r_addend; /* Addend */ -} Elf64_Rela; - -/* How to extract and insert information held in the r_info field. */ - -#define ELF32_R_SYM(val) ((val) >> 8) -#define ELF32_R_TYPE(val) ((val) & 0xff) -#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) - -/* Program segment header. */ - -typedef struct -{ - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -typedef struct -{ - Elf64_Word p_type; /* Segment type */ - Elf64_Word p_flags; /* Segment flags */ - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment */ -} Elf64_Phdr; - -/* Special value for e_phnum. This indicates that the real number of - program headers is too large to fit into e_phnum. Instead the real - value is in the field sh_info of section 0. */ - -#define PN_XNUM 0xffff - -/* Legal values for p_type (segment type). */ - -#define PT_NULL 0 /* Program header table entry unused */ -#define PT_LOAD 1 /* Loadable program segment */ -#define PT_DYNAMIC 2 /* Dynamic linking information */ -#define PT_INTERP 3 /* Program interpreter */ -#define PT_NOTE 4 /* Auxiliary information */ -#define PT_SHLIB 5 /* Reserved */ -#define PT_PHDR 6 /* Entry for header table itself */ -#define PT_TLS 7 /* Thread-local storage segment */ -#define PT_NUM 8 /* Number of defined types */ -#define PT_LOOS 0x60000000 /* Start of OS-specific */ -#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ -#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ -#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ -#define PT_LOSUNW 0x6ffffffa -#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ -#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ -#define PT_HISUNW 0x6fffffff -#define PT_HIOS 0x6fffffff /* End of OS-specific */ -#define PT_LOPROC 0x70000000 /* Start of processor-specific */ -#define PT_HIPROC 0x7fffffff /* End of processor-specific */ - -/* Legal values for p_flags (segment flags). */ - -#define PF_X (1 << 0) /* Segment is executable */ -#define PF_W (1 << 1) /* Segment is writable */ -#define PF_R (1 << 2) /* Segment is readable */ -#define PF_MASKOS 0x0ff00000 /* OS-specific */ -#define PF_MASKPROC 0xf0000000 /* Processor-specific */ - -/* Legal values for note segment descriptor types for core files. */ - -#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ -#define NT_PRFPREG 2 /* Contains copy of fpregset - struct. */ -#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ -#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ -#define NT_PRXREG 4 /* Contains copy of prxregset struct */ -#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ -#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ -#define NT_AUXV 6 /* Contains copy of auxv array */ -#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ -#define NT_ASRS 8 /* Contains copy of asrset struct */ -#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ -#define NT_PSINFO 13 /* Contains copy of psinfo struct */ -#define NT_PRCRED 14 /* Contains copy of prcred struct */ -#define NT_UTSNAME 15 /* Contains copy of utsname struct */ -#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ -#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ -#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ -#define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, - size might increase */ -#define NT_FILE 0x46494c45 /* Contains information about mapped - files */ -#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ -#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ -#define NT_PPC_TAR 0x103 /* Target Address Register */ -#define NT_PPC_PPR 0x104 /* Program Priority Register */ -#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ -#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ -#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ -#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ -#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ -#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ -#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ -#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ -#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address - Register */ -#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority - Register */ -#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control - Register */ -#define NT_PPC_PKEY 0x110 /* Memory Protection Keys - registers. */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ -#define NT_S390_TIMER 0x301 /* s390 timer register */ -#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ -#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ -#define NT_S390_CTRS 0x304 /* s390 control registers */ -#define NT_S390_PREFIX 0x305 /* s390 prefix register */ -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ -#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ -#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 - upper half. */ -#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31. */ -#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers. */ -#define NT_S390_GS_BC 0x30c /* s390 guarded storage - broadcast control block. */ -#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation. */ -#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ -#define NT_ARM_TLS 0x401 /* ARM TLS register */ -#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ -#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ -#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ -#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension - registers */ -#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note. */ -#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers. */ -#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode. */ - -/* Legal values for the note segment descriptor types for object files. */ - -#define NT_VERSION 1 /* Contains a version string. */ - - -/* Dynamic section entry. */ - -typedef struct -{ - Elf32_Sword d_tag; /* Dynamic entry type */ - union - { - Elf32_Word d_val; /* Integer value */ - Elf32_Addr d_ptr; /* Address value */ - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* Dynamic entry type */ - union - { - Elf64_Xword d_val; /* Integer value */ - Elf64_Addr d_ptr; /* Address value */ - } d_un; -} Elf64_Dyn; - -/* Legal values for d_tag (dynamic entry type). */ - -#define DT_NULL 0 /* Marks end of dynamic section */ -#define DT_NEEDED 1 /* Name of needed library */ -#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ -#define DT_PLTGOT 3 /* Processor defined value */ -#define DT_HASH 4 /* Address of symbol hash table */ -#define DT_STRTAB 5 /* Address of string table */ -#define DT_SYMTAB 6 /* Address of symbol table */ -#define DT_RELA 7 /* Address of Rela relocs */ -#define DT_RELASZ 8 /* Total size of Rela relocs */ -#define DT_RELAENT 9 /* Size of one Rela reloc */ -#define DT_STRSZ 10 /* Size of string table */ -#define DT_SYMENT 11 /* Size of one symbol table entry */ -#define DT_INIT 12 /* Address of init function */ -#define DT_FINI 13 /* Address of termination function */ -#define DT_SONAME 14 /* Name of shared object */ -#define DT_RPATH 15 /* Library search path (deprecated) */ -#define DT_SYMBOLIC 16 /* Start symbol search here */ -#define DT_REL 17 /* Address of Rel relocs */ -#define DT_RELSZ 18 /* Total size of Rel relocs */ -#define DT_RELENT 19 /* Size of one Rel reloc */ -#define DT_PLTREL 20 /* Type of reloc in PLT */ -#define DT_DEBUG 21 /* For debugging; unspecified */ -#define DT_TEXTREL 22 /* Reloc might modify .text */ -#define DT_JMPREL 23 /* Address of PLT relocs */ -#define DT_BIND_NOW 24 /* Process relocations of object */ -#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ -#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ -#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ -#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ -#define DT_RUNPATH 29 /* Library search path */ -#define DT_FLAGS 30 /* Flags for the object being loaded */ -#define DT_ENCODING 32 /* Start of encoded range */ -#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ -#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ -#define DT_SYMTAB_SHNDX 34 /* Address of SYMTAB_SHNDX section */ -#define DT_NUM 35 /* Number used */ -#define DT_LOOS 0x6000000d /* Start of OS-specific */ -#define DT_HIOS 0x6ffff000 /* End of OS-specific */ -#define DT_LOPROC 0x70000000 /* Start of processor-specific */ -#define DT_HIPROC 0x7fffffff /* End of processor-specific */ -#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ - -/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the - Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's - approach. */ -#define DT_VALRNGLO 0x6ffffd00 -#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ -#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ -#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ -#define DT_CHECKSUM 0x6ffffdf8 -#define DT_PLTPADSZ 0x6ffffdf9 -#define DT_MOVEENT 0x6ffffdfa -#define DT_MOVESZ 0x6ffffdfb -#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ -#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting - the following DT_* entry. */ -#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ -#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ -#define DT_VALRNGHI 0x6ffffdff -#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ -#define DT_VALNUM 12 - -/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the - Dyn.d_un.d_ptr field of the Elf*_Dyn structure. - - If any adjustment is made to the ELF object after it has been - built these entries will need to be adjusted. */ -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ -#define DT_TLSDESC_PLT 0x6ffffef6 -#define DT_TLSDESC_GOT 0x6ffffef7 -#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ -#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ -#define DT_CONFIG 0x6ffffefa /* Configuration information. */ -#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ -#define DT_AUDIT 0x6ffffefc /* Object auditing. */ -#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ -#define DT_MOVETAB 0x6ffffefe /* Move table. */ -#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ -#define DT_ADDRNUM 11 - -/* The versioning entry types. The next are defined as part of the - GNU extension. */ -#define DT_VERSYM 0x6ffffff0 - -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa - -/* These were chosen by Sun. */ -#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ -#define DT_VERDEF 0x6ffffffc /* Address of version definition - table */ -#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ -#define DT_VERNEED 0x6ffffffe /* Address of table with needed - versions */ -#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ -#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ -#define DT_VERSIONTAGNUM 16 - -/* Sun added these machine-independent extensions in the "processor-specific" - range. Be compatible. */ -#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ -#define DT_FILTER 0x7fffffff /* Shared object to get values from */ -#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) -#define DT_EXTRANUM 3 - -/* Values of `d_un.d_val' in the DT_FLAGS entry. */ -#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ -#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ -#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ -#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ -#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ - -/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 - entry in the dynamic section. */ -#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ -#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ -#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ -#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ -#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ -#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ -#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ -#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ -#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ -#define DF_1_TRANS 0x00000200 -#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ -#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ -#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ -#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ -#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ -#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ -#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ -#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ -#define DF_1_IGNMULDEF 0x00040000 -#define DF_1_NOKSYMS 0x00080000 -#define DF_1_NOHDR 0x00100000 -#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ -#define DF_1_NORELOC 0x00400000 -#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ -#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ -#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ -#define DF_1_STUB 0x04000000 -#define DF_1_PIE 0x08000000 - -/* Flags for the feature selection in DT_FEATURE_1. */ -#define DTF_1_PARINIT 0x00000001 -#define DTF_1_CONFEXP 0x00000002 - -/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ -#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ -#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not - generally available. */ - -/* Version definition sections. */ - -typedef struct -{ - Elf32_Half vd_version; /* Version revision */ - Elf32_Half vd_flags; /* Version information */ - Elf32_Half vd_ndx; /* Version Index */ - Elf32_Half vd_cnt; /* Number of associated aux entries */ - Elf32_Word vd_hash; /* Version name hash value */ - Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf32_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf32_Verdef; - -typedef struct -{ - Elf64_Half vd_version; /* Version revision */ - Elf64_Half vd_flags; /* Version information */ - Elf64_Half vd_ndx; /* Version Index */ - Elf64_Half vd_cnt; /* Number of associated aux entries */ - Elf64_Word vd_hash; /* Version name hash value */ - Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ - Elf64_Word vd_next; /* Offset in bytes to next verdef - entry */ -} Elf64_Verdef; - - -/* Legal values for vd_version (version revision). */ -#define VER_DEF_NONE 0 /* No version */ -#define VER_DEF_CURRENT 1 /* Current version */ -#define VER_DEF_NUM 2 /* Given version number */ - -/* Legal values for vd_flags (version information flags). */ -#define VER_FLG_BASE 0x1 /* Version definition of file itself */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - -/* Versym symbol index values. */ -#define VER_NDX_LOCAL 0 /* Symbol is local. */ -#define VER_NDX_GLOBAL 1 /* Symbol is global. */ -#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ -#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ - -/* Auxialiary version information. */ - -typedef struct -{ - Elf32_Word vda_name; /* Version or dependency names */ - Elf32_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf32_Verdaux; - -typedef struct -{ - Elf64_Word vda_name; /* Version or dependency names */ - Elf64_Word vda_next; /* Offset in bytes to next verdaux - entry */ -} Elf64_Verdaux; - - -/* Version dependency section. */ - -typedef struct -{ - Elf32_Half vn_version; /* Version of structure */ - Elf32_Half vn_cnt; /* Number of associated aux entries */ - Elf32_Word vn_file; /* Offset of filename for this - dependency */ - Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf32_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf32_Verneed; - -typedef struct -{ - Elf64_Half vn_version; /* Version of structure */ - Elf64_Half vn_cnt; /* Number of associated aux entries */ - Elf64_Word vn_file; /* Offset of filename for this - dependency */ - Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ - Elf64_Word vn_next; /* Offset in bytes to next verneed - entry */ -} Elf64_Verneed; - - -/* Legal values for vn_version (version revision). */ -#define VER_NEED_NONE 0 /* No version */ -#define VER_NEED_CURRENT 1 /* Current version */ -#define VER_NEED_NUM 2 /* Given version number */ - -/* Auxiliary needed version information. */ - -typedef struct -{ - Elf32_Word vna_hash; /* Hash value of dependency name */ - Elf32_Half vna_flags; /* Dependency specific information */ - Elf32_Half vna_other; /* Unused */ - Elf32_Word vna_name; /* Dependency name string offset */ - Elf32_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf32_Vernaux; - -typedef struct -{ - Elf64_Word vna_hash; /* Hash value of dependency name */ - Elf64_Half vna_flags; /* Dependency specific information */ - Elf64_Half vna_other; /* Unused */ - Elf64_Word vna_name; /* Dependency name string offset */ - Elf64_Word vna_next; /* Offset in bytes to next vernaux - entry */ -} Elf64_Vernaux; - - -/* Legal values for vna_flags. */ -#define VER_FLG_WEAK 0x2 /* Weak version identifier */ - - -/* Auxiliary vector. */ - -/* This vector is normally only used by the program interpreter. The - usual definition in an ABI supplement uses the name auxv_t. The - vector is not usually defined in a standard file, but it - can't hurt. We rename it to avoid conflicts. The sizes of these - types are an arrangement between the exec server and the program - interpreter, so we don't fully specify them here. */ - -typedef struct -{ - uint32_t a_type; /* Entry type */ - union - { - uint32_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf32_auxv_t; - -typedef struct -{ - uint64_t a_type; /* Entry type */ - union - { - uint64_t a_val; /* Integer value */ - /* We use to have pointer elements added here. We cannot do that, - though, since it does not work when using 32-bit definitions - on 64-bit platforms and vice versa. */ - } a_un; -} Elf64_auxv_t; - -/* Legal values for a_type (entry type). */ - -#define AT_NULL 0 /* End of vector */ -#define AT_IGNORE 1 /* Entry should be ignored */ -#define AT_EXECFD 2 /* File descriptor of program */ -#define AT_PHDR 3 /* Program headers for program */ -#define AT_PHENT 4 /* Size of program header entry */ -#define AT_PHNUM 5 /* Number of program headers */ -#define AT_PAGESZ 6 /* System page size */ -#define AT_BASE 7 /* Base address of interpreter */ -#define AT_FLAGS 8 /* Flags */ -#define AT_ENTRY 9 /* Entry point of program */ -#define AT_NOTELF 10 /* Program is not ELF */ -#define AT_UID 11 /* Real uid */ -#define AT_EUID 12 /* Effective uid */ -#define AT_GID 13 /* Real gid */ -#define AT_EGID 14 /* Effective gid */ -#define AT_CLKTCK 17 /* Frequency of times() */ - -/* Some more special a_type values describing the hardware. */ -#define AT_PLATFORM 15 /* String identifying platform. */ -#define AT_HWCAP 16 /* Machine-dependent hints about - processor capabilities. */ - -/* This entry gives some information about the FPU initialization - performed by the kernel. */ -#define AT_FPUCW 18 /* Used FPU control word. */ - -/* Cache block sizes. */ -#define AT_DCACHEBSIZE 19 /* Data cache block size. */ -#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ -#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ - -/* A special ignored value for PPC, used by the kernel to control the - interpretation of the AUXV. Must be > 16. */ -#define AT_IGNOREPPC 22 /* Entry should be ignored. */ - -#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ - -#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ - -#define AT_RANDOM 25 /* Address of 16 random bytes. */ - -#define AT_HWCAP2 26 /* More machine-dependent hints about - processor capabilities. */ - -#define AT_EXECFN 31 /* Filename of executable. */ - -/* Pointer to the global system page used for system calls and other - nice things. */ -#define AT_SYSINFO 32 -#define AT_SYSINFO_EHDR 33 - -/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains - log2 of line size; mask those to get cache size. */ -#define AT_L1I_CACHESHAPE 34 -#define AT_L1D_CACHESHAPE 35 -#define AT_L2_CACHESHAPE 36 -#define AT_L3_CACHESHAPE 37 - -/* Shapes of the caches, with more room to describe them. - *GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits - and the cache associativity in the next 16 bits. */ -#define AT_L1I_CACHESIZE 40 -#define AT_L1I_CACHEGEOMETRY 41 -#define AT_L1D_CACHESIZE 42 -#define AT_L1D_CACHEGEOMETRY 43 -#define AT_L2_CACHESIZE 44 -#define AT_L2_CACHEGEOMETRY 45 -#define AT_L3_CACHESIZE 46 -#define AT_L3_CACHEGEOMETRY 47 - -#define AT_MINSIGSTKSZ 51 /* Stack needed for signal delivery - (AArch64). */ - -/* Note section contents. Each entry in the note section begins with - a header of a fixed form. */ - -typedef struct -{ - Elf32_Word n_namesz; /* Length of the note's name. */ - Elf32_Word n_descsz; /* Length of the note's descriptor. */ - Elf32_Word n_type; /* Type of the note. */ -} Elf32_Nhdr; - -typedef struct -{ - Elf64_Word n_namesz; /* Length of the note's name. */ - Elf64_Word n_descsz; /* Length of the note's descriptor. */ - Elf64_Word n_type; /* Type of the note. */ -} Elf64_Nhdr; - -/* Known names of notes. */ - -/* Solaris entries in the note section have this name. */ -#define ELF_NOTE_SOLARIS "SUNW Solaris" - -/* Note entries for GNU systems have this name. */ -#define ELF_NOTE_GNU "GNU" - - -/* Defined types of notes for Solaris. */ - -/* Value of descriptor (one word) is desired pagesize for the binary. */ -#define ELF_NOTE_PAGESIZE_HINT 1 - - -/* Defined note types for GNU systems. */ - -/* ABI information. The descriptor consists of words: - word 0: OS descriptor - word 1: major version of the ABI - word 2: minor version of the ABI - word 3: subminor version of the ABI -*/ -#define NT_GNU_ABI_TAG 1 -#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ - -/* Known OSes. These values can appear in word 0 of an - NT_GNU_ABI_TAG note section entry. */ -#define ELF_NOTE_OS_LINUX 0 -#define ELF_NOTE_OS_GNU 1 -#define ELF_NOTE_OS_SOLARIS2 2 -#define ELF_NOTE_OS_FREEBSD 3 - -/* Synthetic hwcap information. The descriptor begins with two words: - word 0: number of entries - word 1: bitmask of enabled entries - Then follow variable-length entries, one byte followed by a - '\0'-terminated hwcap name string. The byte gives the bit - number to test if enabled, (1U << bit) & bitmask. */ -#define NT_GNU_HWCAP 2 - -/* Build ID bits as generated by ld --build-id. - The descriptor consists of any nonzero number of bytes. */ -#define NT_GNU_BUILD_ID 3 - -/* Version note generated by GNU gold containing a version string. */ -#define NT_GNU_GOLD_VERSION 4 - -/* Program property. */ -#define NT_GNU_PROPERTY_TYPE_0 5 - -/* Note section name of program property. */ -#define NOTE_GNU_PROPERTY_SECTION_NAME ".note.gnu.property" - -/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */ - -/* Stack size. */ -#define GNU_PROPERTY_STACK_SIZE 1 -/* No copy relocation on protected data symbol. */ -#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2 - -/* Processor-specific semantics, lo */ -#define GNU_PROPERTY_LOPROC 0xc0000000 -/* Processor-specific semantics, hi */ -#define GNU_PROPERTY_HIPROC 0xdfffffff -/* Application-specific semantics, lo */ -#define GNU_PROPERTY_LOUSER 0xe0000000 -/* Application-specific semantics, hi */ -#define GNU_PROPERTY_HIUSER 0xffffffff - -/* The x86 instruction sets indicated by the corresponding bits are - used in program. Their support in the hardware is optional. */ -#define GNU_PROPERTY_X86_ISA_1_USED 0xc0000000 -/* The x86 instruction sets indicated by the corresponding bits are - used in program and they must be supported by the hardware. */ -#define GNU_PROPERTY_X86_ISA_1_NEEDED 0xc0000001 -/* X86 processor-specific features used in program. */ -#define GNU_PROPERTY_X86_FEATURE_1_AND 0xc0000002 - -#define GNU_PROPERTY_X86_ISA_1_486 (1U << 0) -#define GNU_PROPERTY_X86_ISA_1_586 (1U << 1) -#define GNU_PROPERTY_X86_ISA_1_686 (1U << 2) -#define GNU_PROPERTY_X86_ISA_1_SSE (1U << 3) -#define GNU_PROPERTY_X86_ISA_1_SSE2 (1U << 4) -#define GNU_PROPERTY_X86_ISA_1_SSE3 (1U << 5) -#define GNU_PROPERTY_X86_ISA_1_SSSE3 (1U << 6) -#define GNU_PROPERTY_X86_ISA_1_SSE4_1 (1U << 7) -#define GNU_PROPERTY_X86_ISA_1_SSE4_2 (1U << 8) -#define GNU_PROPERTY_X86_ISA_1_AVX (1U << 9) -#define GNU_PROPERTY_X86_ISA_1_AVX2 (1U << 10) -#define GNU_PROPERTY_X86_ISA_1_AVX512F (1U << 11) -#define GNU_PROPERTY_X86_ISA_1_AVX512CD (1U << 12) -#define GNU_PROPERTY_X86_ISA_1_AVX512ER (1U << 13) -#define GNU_PROPERTY_X86_ISA_1_AVX512PF (1U << 14) -#define GNU_PROPERTY_X86_ISA_1_AVX512VL (1U << 15) -#define GNU_PROPERTY_X86_ISA_1_AVX512DQ (1U << 16) -#define GNU_PROPERTY_X86_ISA_1_AVX512BW (1U << 17) - -/* This indicates that all executable sections are compatible with - IBT. */ -#define GNU_PROPERTY_X86_FEATURE_1_IBT (1U << 0) -/* This indicates that all executable sections are compatible with - SHSTK. */ -#define GNU_PROPERTY_X86_FEATURE_1_SHSTK (1U << 1) - -/* Move records. */ -typedef struct -{ - Elf32_Xword m_value; /* Symbol value. */ - Elf32_Word m_info; /* Size and index. */ - Elf32_Word m_poffset; /* Symbol offset. */ - Elf32_Half m_repeat; /* Repeat count. */ - Elf32_Half m_stride; /* Stride info. */ -} Elf32_Move; - -typedef struct -{ - Elf64_Xword m_value; /* Symbol value. */ - Elf64_Xword m_info; /* Size and index. */ - Elf64_Xword m_poffset; /* Symbol offset. */ - Elf64_Half m_repeat; /* Repeat count. */ - Elf64_Half m_stride; /* Stride info. */ -} Elf64_Move; - -/* Macro to construct move records. */ -#define ELF32_M_SYM(info) ((info) >> 8) -#define ELF32_M_SIZE(info) ((unsigned char) (info)) -#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) - -#define ELF64_M_SYM(info) ELF32_M_SYM (info) -#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) -#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) - - -/* Motorola 68k specific definitions. */ - -/* Values for Elf32_Ehdr.e_flags. */ -#define EF_CPU32 0x00810000 - -/* m68k relocs. */ - -#define R_68K_NONE 0 /* No reloc */ -#define R_68K_32 1 /* Direct 32 bit */ -#define R_68K_16 2 /* Direct 16 bit */ -#define R_68K_8 3 /* Direct 8 bit */ -#define R_68K_PC32 4 /* PC relative 32 bit */ -#define R_68K_PC16 5 /* PC relative 16 bit */ -#define R_68K_PC8 6 /* PC relative 8 bit */ -#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ -#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ -#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ -#define R_68K_GOT32O 10 /* 32 bit GOT offset */ -#define R_68K_GOT16O 11 /* 16 bit GOT offset */ -#define R_68K_GOT8O 12 /* 8 bit GOT offset */ -#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ -#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ -#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ -#define R_68K_PLT32O 16 /* 32 bit PLT offset */ -#define R_68K_PLT16O 17 /* 16 bit PLT offset */ -#define R_68K_PLT8O 18 /* 8 bit PLT offset */ -#define R_68K_COPY 19 /* Copy symbol at runtime */ -#define R_68K_GLOB_DAT 20 /* Create GOT entry */ -#define R_68K_JMP_SLOT 21 /* Create PLT entry */ -#define R_68K_RELATIVE 22 /* Adjust by program base */ -#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ -#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ -#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ -#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ -#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ -#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ -#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ -#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ -#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ -#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ -#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ -#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ -#define R_68K_TLS_LE32 37 /* 32 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE16 38 /* 16 bit offset relative to - static TLS block */ -#define R_68K_TLS_LE8 39 /* 8 bit offset relative to - static TLS block */ -#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ -#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ -#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ -/* Keep this the last entry. */ -#define R_68K_NUM 43 - -/* Intel 80386 specific definitions. */ - -/* i386 relocs. */ - -#define R_386_NONE 0 /* No reloc */ -#define R_386_32 1 /* Direct 32 bit */ -#define R_386_PC32 2 /* PC relative 32 bit */ -#define R_386_GOT32 3 /* 32 bit GOT entry */ -#define R_386_PLT32 4 /* 32 bit PLT address */ -#define R_386_COPY 5 /* Copy symbol at runtime */ -#define R_386_GLOB_DAT 6 /* Create GOT entry */ -#define R_386_JMP_SLOT 7 /* Create PLT entry */ -#define R_386_RELATIVE 8 /* Adjust by program base */ -#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ -#define R_386_32PLT 11 -#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ -#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS - block offset */ -#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block - offset */ -#define R_386_TLS_LE 17 /* Offset relative to static TLS - block */ -#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of - general dynamic thread local data */ -#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of - local dynamic thread local data - in LE code */ -#define R_386_16 20 -#define R_386_PC16 21 -#define R_386_8 22 -#define R_386_PC8 23 -#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic - thread local data */ -#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ -#define R_386_TLS_GD_CALL 26 /* Relocation for call to - __tls_get_addr() */ -#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ -#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic - thread local data in LE code */ -#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ -#define R_386_TLS_LDM_CALL 30 /* Relocation for call to - __tls_get_addr() in LDM code */ -#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ -#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ -#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS - block offset */ -#define R_386_TLS_LE_32 34 /* Negated offset relative to static - TLS block */ -#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ -#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ -#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ -#define R_386_SIZE32 38 /* 32-bit symbol size */ -#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ -#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS - descriptor for - relaxation. */ -#define R_386_TLS_DESC 41 /* TLS descriptor containing - pointer to code and to - argument, returning the TLS - offset for the symbol. */ -#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ -#define R_386_GOT32X 43 /* Load from 32 bit GOT entry, - relaxable. */ -/* Keep this the last entry. */ -#define R_386_NUM 44 - -/* SUN SPARC specific definitions. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ - -/* Values for Elf64_Ehdr.e_flags. */ - -#define EF_SPARCV9_MM 3 -#define EF_SPARCV9_TSO 0 -#define EF_SPARCV9_PSO 1 -#define EF_SPARCV9_RMO 2 -#define EF_SPARC_LEDATA 0x800000 /* little endian data */ -#define EF_SPARC_EXT_MASK 0xFFFF00 -#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ -#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ -#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ -#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ - -/* SPARC relocs. */ - -#define R_SPARC_NONE 0 /* No reloc */ -#define R_SPARC_8 1 /* Direct 8 bit */ -#define R_SPARC_16 2 /* Direct 16 bit */ -#define R_SPARC_32 3 /* Direct 32 bit */ -#define R_SPARC_DISP8 4 /* PC relative 8 bit */ -#define R_SPARC_DISP16 5 /* PC relative 16 bit */ -#define R_SPARC_DISP32 6 /* PC relative 32 bit */ -#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ -#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ -#define R_SPARC_HI22 9 /* High 22 bit */ -#define R_SPARC_22 10 /* Direct 22 bit */ -#define R_SPARC_13 11 /* Direct 13 bit */ -#define R_SPARC_LO10 12 /* Truncated 10 bit */ -#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ -#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ -#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ -#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ -#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ -#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ -#define R_SPARC_COPY 19 /* Copy symbol at runtime */ -#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ -#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ -#define R_SPARC_RELATIVE 22 /* Adjust by program base */ -#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ - -/* Additional Sparc64 relocs. */ - -#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ -#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ -#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ -#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ -#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ -#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ -#define R_SPARC_10 30 /* Direct 10 bit */ -#define R_SPARC_11 31 /* Direct 11 bit */ -#define R_SPARC_64 32 /* Direct 64 bit */ -#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ -#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ -#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ -#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ -#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ -#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ -#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ -#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ -#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ -#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ -#define R_SPARC_7 43 /* Direct 7 bit */ -#define R_SPARC_5 44 /* Direct 5 bit */ -#define R_SPARC_6 45 /* Direct 6 bit */ -#define R_SPARC_DISP64 46 /* PC relative 64 bit */ -#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ -#define R_SPARC_HIX22 48 /* High 22 bit complemented */ -#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ -#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ -#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ -#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ -#define R_SPARC_REGISTER 53 /* Global register usage */ -#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ -#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ -#define R_SPARC_TLS_GD_HI22 56 -#define R_SPARC_TLS_GD_LO10 57 -#define R_SPARC_TLS_GD_ADD 58 -#define R_SPARC_TLS_GD_CALL 59 -#define R_SPARC_TLS_LDM_HI22 60 -#define R_SPARC_TLS_LDM_LO10 61 -#define R_SPARC_TLS_LDM_ADD 62 -#define R_SPARC_TLS_LDM_CALL 63 -#define R_SPARC_TLS_LDO_HIX22 64 -#define R_SPARC_TLS_LDO_LOX10 65 -#define R_SPARC_TLS_LDO_ADD 66 -#define R_SPARC_TLS_IE_HI22 67 -#define R_SPARC_TLS_IE_LO10 68 -#define R_SPARC_TLS_IE_LD 69 -#define R_SPARC_TLS_IE_LDX 70 -#define R_SPARC_TLS_IE_ADD 71 -#define R_SPARC_TLS_LE_HIX22 72 -#define R_SPARC_TLS_LE_LOX10 73 -#define R_SPARC_TLS_DTPMOD32 74 -#define R_SPARC_TLS_DTPMOD64 75 -#define R_SPARC_TLS_DTPOFF32 76 -#define R_SPARC_TLS_DTPOFF64 77 -#define R_SPARC_TLS_TPOFF32 78 -#define R_SPARC_TLS_TPOFF64 79 -#define R_SPARC_GOTDATA_HIX22 80 -#define R_SPARC_GOTDATA_LOX10 81 -#define R_SPARC_GOTDATA_OP_HIX22 82 -#define R_SPARC_GOTDATA_OP_LOX10 83 -#define R_SPARC_GOTDATA_OP 84 -#define R_SPARC_H34 85 -#define R_SPARC_SIZE32 86 -#define R_SPARC_SIZE64 87 -#define R_SPARC_WDISP10 88 -#define R_SPARC_JMP_IREL 248 -#define R_SPARC_IRELATIVE 249 -#define R_SPARC_GNU_VTINHERIT 250 -#define R_SPARC_GNU_VTENTRY 251 -#define R_SPARC_REV32 252 -/* Keep this the last entry. */ -#define R_SPARC_NUM 253 - -/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ - -#define DT_SPARC_REGISTER 0x70000001 -#define DT_SPARC_NUM 2 - -/* MIPS R3000 specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */ -#define EF_MIPS_PIC 2 /* Contains PIC code. */ -#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */ -#define EF_MIPS_XGOT 8 -#define EF_MIPS_64BIT_WHIRL 16 -#define EF_MIPS_ABI2 32 -#define EF_MIPS_ABI_ON32 64 -#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */ -#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */ -#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */ - -/* Legal values for MIPS architecture level. */ - -#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ -#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ -#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ -#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ -#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ -#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ -#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ -#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ -#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ - -/* The following are unofficial names and should not be used. */ - -#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1 -#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2 -#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3 -#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4 -#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5 -#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32 -#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64 - -/* Special section indices. */ - -#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */ -#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ -#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ -#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */ -#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */ -#define SHT_MIPS_MSYM 0x70000001 -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */ -#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ -#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */ -#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */ -#define SHT_MIPS_PACKAGE 0x70000007 -#define SHT_MIPS_PACKSYM 0x70000008 -#define SHT_MIPS_RELD 0x70000009 -#define SHT_MIPS_IFACE 0x7000000b -#define SHT_MIPS_CONTENT 0x7000000c -#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ -#define SHT_MIPS_SHDR 0x70000010 -#define SHT_MIPS_FDESC 0x70000011 -#define SHT_MIPS_EXTSYM 0x70000012 -#define SHT_MIPS_DENSE 0x70000013 -#define SHT_MIPS_PDESC 0x70000014 -#define SHT_MIPS_LOCSYM 0x70000015 -#define SHT_MIPS_AUXSYM 0x70000016 -#define SHT_MIPS_OPTSYM 0x70000017 -#define SHT_MIPS_LOCSTR 0x70000018 -#define SHT_MIPS_LINE 0x70000019 -#define SHT_MIPS_RFDESC 0x7000001a -#define SHT_MIPS_DELTASYM 0x7000001b -#define SHT_MIPS_DELTAINST 0x7000001c -#define SHT_MIPS_DELTACLASS 0x7000001d -#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ -#define SHT_MIPS_DELTADECL 0x7000001f -#define SHT_MIPS_SYMBOL_LIB 0x70000020 -#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ -#define SHT_MIPS_TRANSLATE 0x70000022 -#define SHT_MIPS_PIXIE 0x70000023 -#define SHT_MIPS_XLATE 0x70000024 -#define SHT_MIPS_XLATE_DEBUG 0x70000025 -#define SHT_MIPS_WHIRL 0x70000026 -#define SHT_MIPS_EH_REGION 0x70000027 -#define SHT_MIPS_XLATE_OLD 0x70000028 -#define SHT_MIPS_PDR_EXCEPTION 0x70000029 - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */ -#define SHF_MIPS_MERGE 0x20000000 -#define SHF_MIPS_ADDR 0x40000000 -#define SHF_MIPS_STRINGS 0x80000000 -#define SHF_MIPS_NOSTRIP 0x08000000 -#define SHF_MIPS_LOCAL 0x04000000 -#define SHF_MIPS_NAMES 0x02000000 -#define SHF_MIPS_NODUPE 0x01000000 - - -/* Symbol tables. */ - -/* MIPS specific values for `st_other'. */ -#define STO_MIPS_DEFAULT 0x0 -#define STO_MIPS_INTERNAL 0x1 -#define STO_MIPS_HIDDEN 0x2 -#define STO_MIPS_PROTECTED 0x3 -#define STO_MIPS_PLT 0x8 -#define STO_MIPS_SC_ALIGN_UNUSED 0xff - -/* MIPS specific values for `st_info'. */ -#define STB_MIPS_SPLIT_COMMON 13 - -/* Entries found in sections of type SHT_MIPS_GPTAB. */ - -typedef union -{ - struct - { - Elf32_Word gt_current_g_value; /* -G value used for compilation. */ - Elf32_Word gt_unused; /* Not used. */ - } gt_header; /* First entry in section. */ - struct - { - Elf32_Word gt_g_value; /* If this value were used for -G. */ - Elf32_Word gt_bytes; /* This many bytes would be used. */ - } gt_entry; /* Subsequent entries in section. */ -} Elf32_gptab; - -/* Entry found in sections of type SHT_MIPS_REGINFO. */ - -typedef struct -{ - Elf32_Word ri_gprmask; /* General registers used. */ - Elf32_Word ri_cprmask[4]; /* Coprocessor registers used. */ - Elf32_Sword ri_gp_value; /* $gp register value. */ -} Elf32_RegInfo; - -/* Entries found in sections of type SHT_MIPS_OPTIONS. */ - -typedef struct -{ - unsigned char kind; /* Determines interpretation of the - variable part of descriptor. */ - unsigned char size; /* Size of descriptor, including header. */ - Elf32_Section section; /* Section header index of section affected, - 0 for global options. */ - Elf32_Word info; /* Kind-specific information. */ -} Elf_Options; - -/* Values for `kind' field in Elf_Options. */ - -#define ODK_NULL 0 /* Undefined. */ -#define ODK_REGINFO 1 /* Register usage information. */ -#define ODK_EXCEPTIONS 2 /* Exception processing options. */ -#define ODK_PAD 3 /* Section padding options. */ -#define ODK_HWPATCH 4 /* Hardware workarounds performed */ -#define ODK_FILL 5 /* record the fill value used by the linker. */ -#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ -#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ -#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ - -/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ - -#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ -#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ -#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ -#define OEX_SMM 0x20000 /* Force sequential memory mode? */ -#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ -#define OEX_PRECISEFP OEX_FPDBUG -#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ - -#define OEX_FPU_INVAL 0x10 -#define OEX_FPU_DIV0 0x08 -#define OEX_FPU_OFLO 0x04 -#define OEX_FPU_UFLO 0x02 -#define OEX_FPU_INEX 0x01 - -/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ - -#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ -#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ -#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ -#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ - -#define OPAD_PREFIX 0x1 -#define OPAD_POSTFIX 0x2 -#define OPAD_SYMBOL 0x4 - -/* Entry found in `.options' section. */ - -typedef struct -{ - Elf32_Word hwp_flags1; /* Extra flags. */ - Elf32_Word hwp_flags2; /* Extra flags. */ -} Elf_Options_Hw; - -/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ - -#define OHWA0_R4KEOP_CHECKED 0x00000001 -#define OHWA1_R4KEOP_CLEAN 0x00000002 - -/* MIPS relocs. */ - -#define R_MIPS_NONE 0 /* No reloc */ -#define R_MIPS_16 1 /* Direct 16 bit */ -#define R_MIPS_32 2 /* Direct 32 bit */ -#define R_MIPS_REL32 3 /* PC relative 32 bit */ -#define R_MIPS_26 4 /* Direct 26 bit shifted */ -#define R_MIPS_HI16 5 /* High 16 bit */ -#define R_MIPS_LO16 6 /* Low 16 bit */ -#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ -#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ -#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ -#define R_MIPS_PC16 10 /* PC relative 16 bit */ -#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ -#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ - -#define R_MIPS_SHIFT5 16 -#define R_MIPS_SHIFT6 17 -#define R_MIPS_64 18 -#define R_MIPS_GOT_DISP 19 -#define R_MIPS_GOT_PAGE 20 -#define R_MIPS_GOT_OFST 21 -#define R_MIPS_GOT_HI16 22 -#define R_MIPS_GOT_LO16 23 -#define R_MIPS_SUB 24 -#define R_MIPS_INSERT_A 25 -#define R_MIPS_INSERT_B 26 -#define R_MIPS_DELETE 27 -#define R_MIPS_HIGHER 28 -#define R_MIPS_HIGHEST 29 -#define R_MIPS_CALL_HI16 30 -#define R_MIPS_CALL_LO16 31 -#define R_MIPS_SCN_DISP 32 -#define R_MIPS_REL16 33 -#define R_MIPS_ADD_IMMEDIATE 34 -#define R_MIPS_PJUMP 35 -#define R_MIPS_RELGOT 36 -#define R_MIPS_JALR 37 -#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ -#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ -#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ -#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ -#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ -#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ -#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ -#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ -#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ -#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ -#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ -#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ -#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ -#define R_MIPS_GLOB_DAT 51 -#define R_MIPS_COPY 126 -#define R_MIPS_JUMP_SLOT 127 -/* Keep this the last entry. */ -#define R_MIPS_NUM 128 - -/* Legal values for p_type field of Elf32_Phdr. */ - -#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */ -#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ -#define PT_MIPS_OPTIONS 0x70000002 -#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */ - -/* Special program header types. */ - -#define PF_MIPS_LOCAL 0x10000000 - -/* Legal values for d_tag field of Elf32_Dyn. */ - -#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ -#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ -#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ -#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ -#define DT_MIPS_FLAGS 0x70000005 /* Flags */ -#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ -#define DT_MIPS_MSYM 0x70000007 -#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ -#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ -#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ -#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ -#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ -#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ -#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ -#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ -#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ -#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ -#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ -#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in - DT_MIPS_DELTA_CLASS. */ -#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ -#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in - DT_MIPS_DELTA_INSTANCE. */ -#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ -#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in - DT_MIPS_DELTA_RELOC. */ -#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta - relocations refer to. */ -#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in - DT_MIPS_DELTA_SYM. */ -#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the - class declaration. */ -#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in - DT_MIPS_DELTA_CLASSSYM. */ -#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ -#define DT_MIPS_PIXIE_INIT 0x70000023 -#define DT_MIPS_SYMBOL_LIB 0x70000024 -#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 -#define DT_MIPS_LOCAL_GOTIDX 0x70000026 -#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 -#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 -#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ -#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ -#define DT_MIPS_DYNSTR_ALIGN 0x7000002b -#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ -#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve - function stored in GOT. */ -#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added - by rld on dlopen() calls. */ -#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ -#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ -#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ -/* The address of .got.plt in an executable using the new non-PIC ABI. */ -#define DT_MIPS_PLTGOT 0x70000032 -/* The base of the PLT in an executable using the new non-PIC ABI if that - PLT is writable. For a non-writable PLT, this is omitted or has a zero - value. */ -#define DT_MIPS_RWPLT 0x70000034 -/* An alternative description of the classic MIPS RLD_MAP that is usable - in a PIE as it stores a relative offset from the address of the tag - rather than an absolute address. */ -#define DT_MIPS_RLD_MAP_REL 0x70000035 -#define DT_MIPS_NUM 0x36 - -/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ - -#define RHF_NONE 0 /* No flags */ -#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ -#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ -#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ -#define RHF_NO_MOVE (1 << 3) -#define RHF_SGI_ONLY (1 << 4) -#define RHF_GUARANTEE_INIT (1 << 5) -#define RHF_DELTA_C_PLUS_PLUS (1 << 6) -#define RHF_GUARANTEE_START_INIT (1 << 7) -#define RHF_PIXIE (1 << 8) -#define RHF_DEFAULT_DELAY_LOAD (1 << 9) -#define RHF_REQUICKSTART (1 << 10) -#define RHF_REQUICKSTARTED (1 << 11) -#define RHF_CORD (1 << 12) -#define RHF_NO_UNRES_UNDEF (1 << 13) -#define RHF_RLD_ORDER_SAFE (1 << 14) - -/* Entries found in sections of type SHT_MIPS_LIBLIST. */ - -typedef struct -{ - Elf32_Word l_name; /* Name (string table index) */ - Elf32_Word l_time_stamp; /* Timestamp */ - Elf32_Word l_checksum; /* Checksum */ - Elf32_Word l_version; /* Interface version */ - Elf32_Word l_flags; /* Flags */ -} Elf32_Lib; - -typedef struct -{ - Elf64_Word l_name; /* Name (string table index) */ - Elf64_Word l_time_stamp; /* Timestamp */ - Elf64_Word l_checksum; /* Checksum */ - Elf64_Word l_version; /* Interface version */ - Elf64_Word l_flags; /* Flags */ -} Elf64_Lib; - - -/* Legal values for l_flags. */ - -#define LL_NONE 0 -#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ -#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ -#define LL_REQUIRE_MINOR (1 << 2) -#define LL_EXPORTS (1 << 3) -#define LL_DELAY_LOAD (1 << 4) -#define LL_DELTA (1 << 5) - -/* Entries found in sections of type SHT_MIPS_CONFLICT. */ - -typedef Elf32_Addr Elf32_Conflict; - -typedef struct -{ - /* Version of flags structure. */ - Elf32_Half version; - /* The level of the ISA: 1-5, 32, 64. */ - unsigned char isa_level; - /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */ - unsigned char isa_rev; - /* The size of general purpose registers. */ - unsigned char gpr_size; - /* The size of co-processor 1 registers. */ - unsigned char cpr1_size; - /* The size of co-processor 2 registers. */ - unsigned char cpr2_size; - /* The floating-point ABI. */ - unsigned char fp_abi; - /* Processor-specific extension. */ - Elf32_Word isa_ext; - /* Mask of ASEs used. */ - Elf32_Word ases; - /* Mask of general flags. */ - Elf32_Word flags1; - Elf32_Word flags2; -} Elf_MIPS_ABIFlags_v0; - -/* Values for the register size bytes of an abi flags structure. */ - -#define MIPS_AFL_REG_NONE 0x00 /* No registers. */ -#define MIPS_AFL_REG_32 0x01 /* 32-bit registers. */ -#define MIPS_AFL_REG_64 0x02 /* 64-bit registers. */ -#define MIPS_AFL_REG_128 0x03 /* 128-bit registers. */ - -/* Masks for the ases word of an ABI flags structure. */ - -#define MIPS_AFL_ASE_DSP 0x00000001 /* DSP ASE. */ -#define MIPS_AFL_ASE_DSPR2 0x00000002 /* DSP R2 ASE. */ -#define MIPS_AFL_ASE_EVA 0x00000004 /* Enhanced VA Scheme. */ -#define MIPS_AFL_ASE_MCU 0x00000008 /* MCU (MicroController) ASE. */ -#define MIPS_AFL_ASE_MDMX 0x00000010 /* MDMX ASE. */ -#define MIPS_AFL_ASE_MIPS3D 0x00000020 /* MIPS-3D ASE. */ -#define MIPS_AFL_ASE_MT 0x00000040 /* MT ASE. */ -#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 /* SmartMIPS ASE. */ -#define MIPS_AFL_ASE_VIRT 0x00000100 /* VZ ASE. */ -#define MIPS_AFL_ASE_MSA 0x00000200 /* MSA ASE. */ -#define MIPS_AFL_ASE_MIPS16 0x00000400 /* MIPS16 ASE. */ -#define MIPS_AFL_ASE_MICROMIPS 0x00000800 /* MICROMIPS ASE. */ -#define MIPS_AFL_ASE_XPA 0x00001000 /* XPA ASE. */ -#define MIPS_AFL_ASE_MASK 0x00001fff /* All ASEs. */ - -/* Values for the isa_ext word of an ABI flags structure. */ - -#define MIPS_AFL_EXT_XLR 1 /* RMI Xlr instruction. */ -#define MIPS_AFL_EXT_OCTEON2 2 /* Cavium Networks Octeon2. */ -#define MIPS_AFL_EXT_OCTEONP 3 /* Cavium Networks OcteonP. */ -#define MIPS_AFL_EXT_LOONGSON_3A 4 /* Loongson 3A. */ -#define MIPS_AFL_EXT_OCTEON 5 /* Cavium Networks Octeon. */ -#define MIPS_AFL_EXT_5900 6 /* MIPS R5900 instruction. */ -#define MIPS_AFL_EXT_4650 7 /* MIPS R4650 instruction. */ -#define MIPS_AFL_EXT_4010 8 /* LSI R4010 instruction. */ -#define MIPS_AFL_EXT_4100 9 /* NEC VR4100 instruction. */ -#define MIPS_AFL_EXT_3900 10 /* Toshiba R3900 instruction. */ -#define MIPS_AFL_EXT_10000 11 /* MIPS R10000 instruction. */ -#define MIPS_AFL_EXT_SB1 12 /* Broadcom SB-1 instruction. */ -#define MIPS_AFL_EXT_4111 13 /* NEC VR4111/VR4181 instruction. */ -#define MIPS_AFL_EXT_4120 14 /* NEC VR4120 instruction. */ -#define MIPS_AFL_EXT_5400 15 /* NEC VR5400 instruction. */ -#define MIPS_AFL_EXT_5500 16 /* NEC VR5500 instruction. */ -#define MIPS_AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */ -#define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */ - -/* Masks for the flags1 word of an ABI flags structure. */ -#define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */ - -/* Object attribute values. */ -enum -{ - /* Not tagged or not using any ABIs affected by the differences. */ - Val_GNU_MIPS_ABI_FP_ANY = 0, - /* Using hard-float -mdouble-float. */ - Val_GNU_MIPS_ABI_FP_DOUBLE = 1, - /* Using hard-float -msingle-float. */ - Val_GNU_MIPS_ABI_FP_SINGLE = 2, - /* Using soft-float. */ - Val_GNU_MIPS_ABI_FP_SOFT = 3, - /* Using -mips32r2 -mfp64. */ - Val_GNU_MIPS_ABI_FP_OLD_64 = 4, - /* Using -mfpxx. */ - Val_GNU_MIPS_ABI_FP_XX = 5, - /* Using -mips32r2 -mfp64. */ - Val_GNU_MIPS_ABI_FP_64 = 6, - /* Using -mips32r2 -mfp64 -mno-odd-spreg. */ - Val_GNU_MIPS_ABI_FP_64A = 7, - /* Maximum allocated FP ABI value. */ - Val_GNU_MIPS_ABI_FP_MAX = 7 -}; - -/* HPPA specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ -#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ -#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ -#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ -#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch - prediction. */ -#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ -#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ - -/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ - -#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ -#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ -#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ - -/* Additional section indeces. */ - -#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared - symbols in ANSI C. */ -#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ -#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ -#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ -#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ -#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ - -#define STT_HP_OPAQUE (STT_LOOS + 0x1) -#define STT_HP_STUB (STT_LOOS + 0x2) - -/* HPPA relocs. */ - -#define R_PARISC_NONE 0 /* No reloc. */ -#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ -#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ -#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ -#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ -#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ -#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ -#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ -#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ -#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ -#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ -#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ -#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ -#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ -#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ -#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ -#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ -#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ -#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ -#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ -#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ -#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ -#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ -#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ -#define R_PARISC_FPTR64 64 /* 64 bits function address. */ -#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ -#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ -#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ -#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ -#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ -#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ -#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ -#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ -#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ -#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ -#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ -#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ -#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ -#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ -#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ -#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ -#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ -#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ -#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ -#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ -#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ -#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LORESERVE 128 -#define R_PARISC_COPY 128 /* Copy relocation. */ -#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ -#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ -#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ -#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ -#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ -#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ -#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ -#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ -#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_GNU_VTENTRY 232 -#define R_PARISC_GNU_VTINHERIT 233 -#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ -#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ -#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ -#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ -#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ -#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ -#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ -#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ -#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ -#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ -#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ -#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L -#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R -#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L -#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R -#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 -#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 -#define R_PARISC_HIRESERVE 255 - -/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ - -#define PT_HP_TLS (PT_LOOS + 0x0) -#define PT_HP_CORE_NONE (PT_LOOS + 0x1) -#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) -#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) -#define PT_HP_CORE_COMM (PT_LOOS + 0x4) -#define PT_HP_CORE_PROC (PT_LOOS + 0x5) -#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) -#define PT_HP_CORE_STACK (PT_LOOS + 0x7) -#define PT_HP_CORE_SHM (PT_LOOS + 0x8) -#define PT_HP_CORE_MMF (PT_LOOS + 0x9) -#define PT_HP_PARALLEL (PT_LOOS + 0x10) -#define PT_HP_FASTBIND (PT_LOOS + 0x11) -#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) -#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) -#define PT_HP_STACK (PT_LOOS + 0x14) - -#define PT_PARISC_ARCHEXT 0x70000000 -#define PT_PARISC_UNWIND 0x70000001 - -/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ - -#define PF_PARISC_SBP 0x08000000 - -#define PF_HP_PAGE_SIZE 0x00100000 -#define PF_HP_FAR_SHARED 0x00200000 -#define PF_HP_NEAR_SHARED 0x00400000 -#define PF_HP_CODE 0x01000000 -#define PF_HP_MODIFY 0x02000000 -#define PF_HP_LAZYSWAP 0x04000000 -#define PF_HP_SBP 0x08000000 - - -/* Alpha specific definitions. */ - -/* Legal values for e_flags field of Elf64_Ehdr. */ - -#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ -#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ - -/* Legal values for sh_type field of Elf64_Shdr. */ - -/* These two are primerily concerned with ECOFF debugging info. */ -#define SHT_ALPHA_DEBUG 0x70000001 -#define SHT_ALPHA_REGINFO 0x70000002 - -/* Legal values for sh_flags field of Elf64_Shdr. */ - -#define SHF_ALPHA_GPREL 0x10000000 - -/* Legal values for st_other field of Elf64_Sym. */ -#define STO_ALPHA_NOPV 0x80 /* No PV required. */ -#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ - -/* Alpha relocs. */ - -#define R_ALPHA_NONE 0 /* No reloc */ -#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ -#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ -#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ -#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ -#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ -#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ -#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ -#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ -#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ -#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ -#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ -#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ -#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ -#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ -#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ -#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ -#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ -#define R_ALPHA_TLS_GD_HI 28 -#define R_ALPHA_TLSGD 29 -#define R_ALPHA_TLS_LDM 30 -#define R_ALPHA_DTPMOD64 31 -#define R_ALPHA_GOTDTPREL 32 -#define R_ALPHA_DTPREL64 33 -#define R_ALPHA_DTPRELHI 34 -#define R_ALPHA_DTPRELLO 35 -#define R_ALPHA_DTPREL16 36 -#define R_ALPHA_GOTTPREL 37 -#define R_ALPHA_TPREL64 38 -#define R_ALPHA_TPRELHI 39 -#define R_ALPHA_TPRELLO 40 -#define R_ALPHA_TPREL16 41 -/* Keep this the last entry. */ -#define R_ALPHA_NUM 46 - -/* Magic values of the LITUSE relocation addend. */ -#define LITUSE_ALPHA_ADDR 0 -#define LITUSE_ALPHA_BASE 1 -#define LITUSE_ALPHA_BYTOFF 2 -#define LITUSE_ALPHA_JSR 3 -#define LITUSE_ALPHA_TLS_GD 4 -#define LITUSE_ALPHA_TLS_LDM 5 - -/* Legal values for d_tag of Elf64_Dyn. */ -#define DT_ALPHA_PLTRO (DT_LOPROC + 0) -#define DT_ALPHA_NUM 1 - -/* PowerPC specific declarations */ - -/* Values for Elf32/64_Ehdr.e_flags. */ -#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ - -/* Cygnus local bits below */ -#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ -#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib - flag */ - -/* PowerPC relocations defined by the ABIs */ -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 /* 32bit absolute address */ -#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ -#define R_PPC_ADDR16 3 /* 16bit absolute address */ -#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ -#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ -#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ -#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 /* PC relative 26 bit */ -#define R_PPC_REL14 11 /* PC relative 16 bit */ -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 - -/* PowerPC relocations defined for the TLS access ABI. */ -#define R_PPC_TLS 67 /* none (sym+add)@tls */ -#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ -#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ -#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ -#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ -#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ -#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ -#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ -#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ -#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ -#define R_PPC_TLSGD 95 /* none (sym+add)@tlsgd */ -#define R_PPC_TLSLD 96 /* none (sym+add)@tlsld */ - -/* The remaining relocs are from the Embedded ELF ABI, and are not - in the SVR4 ELF ABI. */ -#define R_PPC_EMB_NADDR32 101 -#define R_PPC_EMB_NADDR16 102 -#define R_PPC_EMB_NADDR16_LO 103 -#define R_PPC_EMB_NADDR16_HI 104 -#define R_PPC_EMB_NADDR16_HA 105 -#define R_PPC_EMB_SDAI16 106 -#define R_PPC_EMB_SDA2I16 107 -#define R_PPC_EMB_SDA2REL 108 -#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ -#define R_PPC_EMB_MRKREF 110 -#define R_PPC_EMB_RELSEC16 111 -#define R_PPC_EMB_RELST_LO 112 -#define R_PPC_EMB_RELST_HI 113 -#define R_PPC_EMB_RELST_HA 114 -#define R_PPC_EMB_BIT_FLD 115 -#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ - -/* Diab tool relocations. */ -#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ -#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ -#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ -#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ -#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ -#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ - -/* GNU extension to support local ifunc. */ -#define R_PPC_IRELATIVE 248 - -/* GNU relocs used in PIC code sequences. */ -#define R_PPC_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* This is a phony reloc to handle any old fashioned TOC16 references - that may still be in object files. */ -#define R_PPC_TOC16 255 - -/* PowerPC specific values for the Dyn d_tag field. */ -#define DT_PPC_GOT (DT_LOPROC + 0) -#define DT_PPC_OPT (DT_LOPROC + 1) -#define DT_PPC_NUM 2 - -/* PowerPC specific values for the DT_PPC_OPT Dyn entry. */ -#define PPC_OPT_TLS 1 - -/* PowerPC64 relocations defined by the ABIs */ -#define R_PPC64_NONE R_PPC_NONE -#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ -#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ -#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ -#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ -#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ -#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ -#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ -#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN -#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN -#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ -#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ -#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN -#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN -#define R_PPC64_GOT16 R_PPC_GOT16 -#define R_PPC64_GOT16_LO R_PPC_GOT16_LO -#define R_PPC64_GOT16_HI R_PPC_GOT16_HI -#define R_PPC64_GOT16_HA R_PPC_GOT16_HA - -#define R_PPC64_COPY R_PPC_COPY -#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT -#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT -#define R_PPC64_RELATIVE R_PPC_RELATIVE - -#define R_PPC64_UADDR32 R_PPC_UADDR32 -#define R_PPC64_UADDR16 R_PPC_UADDR16 -#define R_PPC64_REL32 R_PPC_REL32 -#define R_PPC64_PLT32 R_PPC_PLT32 -#define R_PPC64_PLTREL32 R_PPC_PLTREL32 -#define R_PPC64_PLT16_LO R_PPC_PLT16_LO -#define R_PPC64_PLT16_HI R_PPC_PLT16_HI -#define R_PPC64_PLT16_HA R_PPC_PLT16_HA - -#define R_PPC64_SECTOFF R_PPC_SECTOFF -#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO -#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI -#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA -#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ -#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ -#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ -#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ -#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ -#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ -#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ -#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ -#define R_PPC64_PLT64 45 /* doubleword64 L + A */ -#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ -#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ -#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ -#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ -#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ -#define R_PPC64_TOC 51 /* doubleword64 .TOC */ -#define R_PPC64_PLTGOT16 52 /* half16* M + A */ -#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ -#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ -#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ - -#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ -#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ -#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ -#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ -#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ -#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ -#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ -#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ -#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ -#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ -#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ - -/* PowerPC64 relocations defined for the TLS access ABI. */ -#define R_PPC64_TLS 67 /* none (sym+add)@tls */ -#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ -#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ -#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ -#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ -#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ -#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ -#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ -#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ -#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ -#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ -#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ -#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ -#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ -#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ -#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ -#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ -#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ -#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ -#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ -#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ -#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ -#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ -#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ -#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ -#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ -#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ -#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ -#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ -#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ -#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ -#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ -#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ -#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ -#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ -#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ -#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */ -#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */ -#define R_PPC64_TOCSAVE 109 /* none */ - -/* Added when HA and HI relocs were changed to report overflows. */ -#define R_PPC64_ADDR16_HIGH 110 -#define R_PPC64_ADDR16_HIGHA 111 -#define R_PPC64_TPREL16_HIGH 112 -#define R_PPC64_TPREL16_HIGHA 113 -#define R_PPC64_DTPREL16_HIGH 114 -#define R_PPC64_DTPREL16_HIGHA 115 - -/* GNU extension to support local ifunc. */ -#define R_PPC64_JMP_IREL 247 -#define R_PPC64_IRELATIVE 248 -#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ -#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ -#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ -#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ - -/* e_flags bits specifying ABI. - 1 for original function descriptor using ABI, - 2 for revised ABI without function descriptors, - 0 for unspecified or not using any features affected by the differences. */ -#define EF_PPC64_ABI 3 - -/* PowerPC64 specific values for the Dyn d_tag field. */ -#define DT_PPC64_GLINK (DT_LOPROC + 0) -#define DT_PPC64_OPD (DT_LOPROC + 1) -#define DT_PPC64_OPDSZ (DT_LOPROC + 2) -#define DT_PPC64_OPT (DT_LOPROC + 3) -#define DT_PPC64_NUM 4 - -/* PowerPC64 specific bits in the DT_PPC64_OPT Dyn entry. */ -#define PPC64_OPT_TLS 1 -#define PPC64_OPT_MULTI_TOC 2 -#define PPC64_OPT_LOCALENTRY 4 - -/* PowerPC64 specific values for the Elf64_Sym st_other field. */ -#define STO_PPC64_LOCAL_BIT 5 -#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) -#define PPC64_LOCAL_ENTRY_OFFSET(other) \ - (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) - - -/* ARM specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_ARM_RELEXEC 0x01 -#define EF_ARM_HASENTRY 0x02 -#define EF_ARM_INTERWORK 0x04 -#define EF_ARM_APCS_26 0x08 -#define EF_ARM_APCS_FLOAT 0x10 -#define EF_ARM_PIC 0x20 -#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ -#define EF_ARM_NEW_ABI 0x80 -#define EF_ARM_OLD_ABI 0x100 -#define EF_ARM_SOFT_FLOAT 0x200 -#define EF_ARM_VFP_FLOAT 0x400 -#define EF_ARM_MAVERICK_FLOAT 0x800 - -#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ -#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ - - -/* Other constants defined in the ARM ELF spec. version B-01. */ -/* NB. These conflict with values defined above. */ -#define EF_ARM_SYMSARESORTED 0x04 -#define EF_ARM_DYNSYMSUSESEGIDX 0x08 -#define EF_ARM_MAPSYMSFIRST 0x10 -#define EF_ARM_EABIMASK 0XFF000000 - -/* Constants defined in AAELF. */ -#define EF_ARM_BE8 0x00800000 -#define EF_ARM_LE8 0x00400000 - -#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) -#define EF_ARM_EABI_UNKNOWN 0x00000000 -#define EF_ARM_EABI_VER1 0x01000000 -#define EF_ARM_EABI_VER2 0x02000000 -#define EF_ARM_EABI_VER3 0x03000000 -#define EF_ARM_EABI_VER4 0x04000000 -#define EF_ARM_EABI_VER5 0x05000000 - -/* Additional symbol types for Thumb. */ -#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ -#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ - -/* ARM-specific values for sh_flags */ -#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ -#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined - in the input to a link step. */ - -/* ARM-specific program header flags */ -#define PF_ARM_SB 0x10000000 /* Segment contains the location - addressed by the static base. */ -#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ -#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ -#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ -#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ - - -/* AArch64 relocs. */ - -#define R_AARCH64_NONE 0 /* No relocation. */ - -/* ILP32 AArch64 relocs. */ -#define R_AARCH64_P32_ABS32 1 /* Direct 32 bit. */ -#define R_AARCH64_P32_COPY 180 /* Copy symbol at runtime. */ -#define R_AARCH64_P32_GLOB_DAT 181 /* Create GOT entry. */ -#define R_AARCH64_P32_JUMP_SLOT 182 /* Create PLT entry. */ -#define R_AARCH64_P32_RELATIVE 183 /* Adjust by program base. */ -#define R_AARCH64_P32_TLS_DTPMOD 184 /* Module number, 32 bit. */ -#define R_AARCH64_P32_TLS_DTPREL 185 /* Module-relative offset, 32 bit. */ -#define R_AARCH64_P32_TLS_TPREL 186 /* TP-relative offset, 32 bit. */ -#define R_AARCH64_P32_TLSDESC 187 /* TLS Descriptor. */ -#define R_AARCH64_P32_IRELATIVE 188 /* STT_GNU_IFUNC relocation. */ - -/* LP64 AArch64 relocs. */ -#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ -#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ -#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ -#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ -#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ -#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ -#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ -#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ -#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ -#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ -#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ -#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ -#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ -#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ -#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ -#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ -#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ -#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ -#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ -#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ -#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ -#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ -#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ -#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ -#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ -#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ -#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ -#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ -#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ -#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ -#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ -#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ -#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ -#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ -#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ -#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ -#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ -#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ -#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ -#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ -#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ -#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ -#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ -#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ -#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ -#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ -#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ -#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ -#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ -#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ -#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ -#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ -#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ -#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ -#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ -#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ -#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ -#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ -#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ -#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ -#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ -#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ -#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ -#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ -#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ -#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ -#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ -#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ -#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ -#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ -#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ -#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ -#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ -#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ -#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ -#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ -#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ -#define R_AARCH64_TLS_DTPMOD 1028 /* Module number, 64 bit. */ -#define R_AARCH64_TLS_DTPREL 1029 /* Module-relative offset, 64 bit. */ -#define R_AARCH64_TLS_TPREL 1030 /* TP-relative offset, 64 bit. */ -#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ -#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ - -/* ARM relocs. */ - -#define R_ARM_NONE 0 /* No reloc */ -#define R_ARM_PC24 1 /* Deprecated PC relative 26 - bit branch. */ -#define R_ARM_ABS32 2 /* Direct 32 bit */ -#define R_ARM_REL32 3 /* PC relative 32 bit */ -#define R_ARM_PC13 4 -#define R_ARM_ABS16 5 /* Direct 16 bit */ -#define R_ARM_ABS12 6 /* Direct 12 bit */ -#define R_ARM_THM_ABS5 7 /* Direct & 0x7C (LDR, STR). */ -#define R_ARM_ABS8 8 /* Direct 8 bit */ -#define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 /* PC relative 24 bit (Thumb32 BL). */ -#define R_ARM_THM_PC8 11 /* PC relative & 0x3FC - (Thumb16 LDR, ADD, ADR). */ -#define R_ARM_AMP_VCALL9 12 -#define R_ARM_SWI24 13 /* Obsolete static relocation. */ -#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ -#define R_ARM_THM_SWI8 14 /* Reserved. */ -#define R_ARM_XPC25 15 /* Reserved. */ -#define R_ARM_THM_XPC22 16 /* Reserved. */ -#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ -#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ -#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ -#define R_ARM_COPY 20 /* Copy symbol at runtime */ -#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ -#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ -#define R_ARM_RELATIVE 23 /* Adjust by program base */ -#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ -#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ -#define R_ARM_GOT32 26 /* 32 bit GOT entry */ -#define R_ARM_PLT32 27 /* Deprecated, 32 bit PLT address. */ -#define R_ARM_CALL 28 /* PC relative 24 bit (BL, BLX). */ -#define R_ARM_JUMP24 29 /* PC relative 24 bit - (B, BL). */ -#define R_ARM_THM_JUMP24 30 /* PC relative 24 bit (Thumb32 B.W). */ -#define R_ARM_BASE_ABS 31 /* Adjust by program base. */ -#define R_ARM_ALU_PCREL_7_0 32 /* Obsolete. */ -#define R_ARM_ALU_PCREL_15_8 33 /* Obsolete. */ -#define R_ARM_ALU_PCREL_23_15 34 /* Obsolete. */ -#define R_ARM_LDR_SBREL_11_0 35 /* Deprecated, prog. base relative. */ -#define R_ARM_ALU_SBREL_19_12 36 /* Deprecated, prog. base relative. */ -#define R_ARM_ALU_SBREL_27_20 37 /* Deprecated, prog. base relative. */ -#define R_ARM_TARGET1 38 -#define R_ARM_SBREL31 39 /* Program base relative. */ -#define R_ARM_V4BX 40 -#define R_ARM_TARGET2 41 -#define R_ARM_PREL31 42 /* 32 bit PC relative. */ -#define R_ARM_MOVW_ABS_NC 43 /* Direct 16-bit (MOVW). */ -#define R_ARM_MOVT_ABS 44 /* Direct high 16-bit (MOVT). */ -#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */ -#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */ -#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW). */ -#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit - (Thumb32 MOVT). */ -#define R_ARM_THM_MOVW_PREL_NC 49 /* PC relative 16 bit - (Thumb32 MOVW). */ -#define R_ARM_THM_MOVT_PREL 50 /* PC relative high 16 bit - (Thumb32 MOVT). */ -#define R_ARM_THM_JUMP19 51 /* PC relative 20 bit - (Thumb32 B.W). */ -#define R_ARM_THM_JUMP6 52 /* PC relative X & 0x7E - (Thumb16 CBZ, CBNZ). */ -#define R_ARM_THM_ALU_PREL_11_0 53 /* PC relative 12 bit - (Thumb32 ADR.W). */ -#define R_ARM_THM_PC12 54 /* PC relative 12 bit - (Thumb32 LDR{D,SB,H,SH}). */ -#define R_ARM_ABS32_NOI 55 /* Direct 32-bit. */ -#define R_ARM_REL32_NOI 56 /* PC relative 32-bit. */ -#define R_ARM_ALU_PC_G0_NC 57 /* PC relative (ADD, SUB). */ -#define R_ARM_ALU_PC_G0 58 /* PC relative (ADD, SUB). */ -#define R_ARM_ALU_PC_G1_NC 59 /* PC relative (ADD, SUB). */ -#define R_ARM_ALU_PC_G1 60 /* PC relative (ADD, SUB). */ -#define R_ARM_ALU_PC_G2 61 /* PC relative (ADD, SUB). */ -#define R_ARM_LDR_PC_G1 62 /* PC relative (LDR,STR,LDRB,STRB). */ -#define R_ARM_LDR_PC_G2 63 /* PC relative (LDR,STR,LDRB,STRB). */ -#define R_ARM_LDRS_PC_G0 64 /* PC relative (STR{D,H}, - LDR{D,SB,H,SH}). */ -#define R_ARM_LDRS_PC_G1 65 /* PC relative (STR{D,H}, - LDR{D,SB,H,SH}). */ -#define R_ARM_LDRS_PC_G2 66 /* PC relative (STR{D,H}, - LDR{D,SB,H,SH}). */ -#define R_ARM_LDC_PC_G0 67 /* PC relative (LDC, STC). */ -#define R_ARM_LDC_PC_G1 68 /* PC relative (LDC, STC). */ -#define R_ARM_LDC_PC_G2 69 /* PC relative (LDC, STC). */ -#define R_ARM_ALU_SB_G0_NC 70 /* Program base relative (ADD,SUB). */ -#define R_ARM_ALU_SB_G0 71 /* Program base relative (ADD,SUB). */ -#define R_ARM_ALU_SB_G1_NC 72 /* Program base relative (ADD,SUB). */ -#define R_ARM_ALU_SB_G1 73 /* Program base relative (ADD,SUB). */ -#define R_ARM_ALU_SB_G2 74 /* Program base relative (ADD,SUB). */ -#define R_ARM_LDR_SB_G0 75 /* Program base relative (LDR, - STR, LDRB, STRB). */ -#define R_ARM_LDR_SB_G1 76 /* Program base relative - (LDR, STR, LDRB, STRB). */ -#define R_ARM_LDR_SB_G2 77 /* Program base relative - (LDR, STR, LDRB, STRB). */ -#define R_ARM_LDRS_SB_G0 78 /* Program base relative - (LDR, STR, LDRB, STRB). */ -#define R_ARM_LDRS_SB_G1 79 /* Program base relative - (LDR, STR, LDRB, STRB). */ -#define R_ARM_LDRS_SB_G2 80 /* Program base relative - (LDR, STR, LDRB, STRB). */ -#define R_ARM_LDC_SB_G0 81 /* Program base relative (LDC,STC). */ -#define R_ARM_LDC_SB_G1 82 /* Program base relative (LDC,STC). */ -#define R_ARM_LDC_SB_G2 83 /* Program base relative (LDC,STC). */ -#define R_ARM_MOVW_BREL_NC 84 /* Program base relative 16 - bit (MOVW). */ -#define R_ARM_MOVT_BREL 85 /* Program base relative high - 16 bit (MOVT). */ -#define R_ARM_MOVW_BREL 86 /* Program base relative 16 - bit (MOVW). */ -#define R_ARM_THM_MOVW_BREL_NC 87 /* Program base relative 16 - bit (Thumb32 MOVW). */ -#define R_ARM_THM_MOVT_BREL 88 /* Program base relative high - 16 bit (Thumb32 MOVT). */ -#define R_ARM_THM_MOVW_BREL 89 /* Program base relative 16 - bit (Thumb32 MOVW). */ -#define R_ARM_TLS_GOTDESC 90 -#define R_ARM_TLS_CALL 91 -#define R_ARM_TLS_DESCSEQ 92 /* TLS relaxation. */ -#define R_ARM_THM_TLS_CALL 93 -#define R_ARM_PLT32_ABS 94 -#define R_ARM_GOT_ABS 95 /* GOT entry. */ -#define R_ARM_GOT_PREL 96 /* PC relative GOT entry. */ -#define R_ARM_GOT_BREL12 97 /* GOT entry relative to GOT - origin (LDR). */ -#define R_ARM_GOTOFF12 98 /* 12 bit, GOT entry relative - to GOT origin (LDR, STR). */ -#define R_ARM_GOTRELAX 99 -#define R_ARM_GNU_VTENTRY 100 -#define R_ARM_GNU_VTINHERIT 101 -#define R_ARM_THM_PC11 102 /* PC relative & 0xFFE (Thumb16 B). */ -#define R_ARM_THM_PC9 103 /* PC relative & 0x1FE - (Thumb16 B/B). */ -#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic - thread local data */ -#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic - thread local data */ -#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS - block */ -#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of - static TLS block offset */ -#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static - TLS block */ -#define R_ARM_TLS_LDO12 109 /* 12 bit relative to TLS - block (LDR, STR). */ -#define R_ARM_TLS_LE12 110 /* 12 bit relative to static - TLS block (LDR, STR). */ -#define R_ARM_TLS_IE12GP 111 /* 12 bit GOT entry relative - to GOT origin (LDR). */ -#define R_ARM_ME_TOO 128 /* Obsolete. */ -#define R_ARM_THM_TLS_DESCSEQ 129 -#define R_ARM_THM_TLS_DESCSEQ16 129 -#define R_ARM_THM_TLS_DESCSEQ32 130 -#define R_ARM_THM_GOT_BREL12 131 /* GOT entry relative to GOT - origin, 12 bit (Thumb32 LDR). */ -#define R_ARM_IRELATIVE 160 -#define R_ARM_RXPC25 249 -#define R_ARM_RSBREL32 250 -#define R_ARM_THM_RPC22 251 -#define R_ARM_RREL32 252 -#define R_ARM_RABS22 253 -#define R_ARM_RPC24 254 -#define R_ARM_RBASE 255 -/* Keep this the last entry. */ -#define R_ARM_NUM 256 - -/* csky */ -#define R_CKCORE_NONE 0 /* no reloc */ -#define R_CKCORE_ADDR32 1 /* direct 32 bit (S + A) */ -#define R_CKCORE_PCRELIMM8BY4 2 /* disp ((S + A - P) >> 2) & 0xff */ -#define R_CKCORE_PCRELIMM11BY2 3 /* disp ((S + A - P) >> 1) & 0x7ff */ -#define R_CKCORE_PCREL32 5 /* 32-bit rel (S + A - P) */ -#define R_CKCORE_PCRELJSR_IMM11BY2 6 /* disp ((S + A - P) >>1) & 0x7ff */ -#define R_CKCORE_RELATIVE 9 /* 32 bit adjust program base(B + A)*/ -#define R_CKCORE_COPY 10 /* 32 bit adjust by program base */ -#define R_CKCORE_GLOB_DAT 11 /* off between got and sym (S) */ -#define R_CKCORE_JUMP_SLOT 12 /* PLT entry (S) */ -#define R_CKCORE_GOTOFF 13 /* offset to GOT (S + A - GOT) */ -#define R_CKCORE_GOTPC 14 /* PC offset to GOT (GOT + A - P) */ -#define R_CKCORE_GOT32 15 /* 32 bit GOT entry (G) */ -#define R_CKCORE_PLT32 16 /* 32 bit PLT entry (G) */ -#define R_CKCORE_ADDRGOT 17 /* GOT entry in GLOB_DAT (GOT + G) */ -#define R_CKCORE_ADDRPLT 18 /* PLT entry in GLOB_DAT (GOT + G) */ -#define R_CKCORE_PCREL_IMM26BY2 19 /* ((S + A - P) >> 1) & 0x3ffffff */ -#define R_CKCORE_PCREL_IMM16BY2 20 /* disp ((S + A - P) >> 1) & 0xffff */ -#define R_CKCORE_PCREL_IMM16BY4 21 /* disp ((S + A - P) >> 2) & 0xffff */ -#define R_CKCORE_PCREL_IMM10BY2 22 /* disp ((S + A - P) >> 1) & 0x3ff */ -#define R_CKCORE_PCREL_IMM10BY4 23 /* disp ((S + A - P) >> 2) & 0x3ff */ -#define R_CKCORE_ADDR_HI16 24 /* high & low 16 bit ADDR */ - /* ((S + A) >> 16) & 0xffff */ -#define R_CKCORE_ADDR_LO16 25 /* (S + A) & 0xffff */ -#define R_CKCORE_GOTPC_HI16 26 /* high & low 16 bit GOTPC */ - /* ((GOT + A - P) >> 16) & 0xffff */ -#define R_CKCORE_GOTPC_LO16 27 /* (GOT + A - P) & 0xffff */ -#define R_CKCORE_GOTOFF_HI16 28 /* high & low 16 bit GOTOFF */ - /* ((S + A - GOT) >> 16) & 0xffff */ -#define R_CKCORE_GOTOFF_LO16 29 /* (S + A - GOT) & 0xffff */ -#define R_CKCORE_GOT12 30 /* 12 bit disp GOT entry (G) */ -#define R_CKCORE_GOT_HI16 31 /* high & low 16 bit GOT */ - /* (G >> 16) & 0xffff */ -#define R_CKCORE_GOT_LO16 32 /* (G & 0xffff) */ -#define R_CKCORE_PLT12 33 /* 12 bit disp PLT entry (G) */ -#define R_CKCORE_PLT_HI16 34 /* high & low 16 bit PLT */ - /* (G >> 16) & 0xffff */ -#define R_CKCORE_PLT_LO16 35 /* G & 0xffff */ -#define R_CKCORE_ADDRGOT_HI16 36 /* high & low 16 bit ADDRGOT */ - /* (GOT + G * 4) & 0xffff */ -#define R_CKCORE_ADDRGOT_LO16 37 /* (GOT + G * 4) & 0xffff */ -#define R_CKCORE_ADDRPLT_HI16 38 /* high & low 16 bit ADDRPLT */ - /* ((GOT + G * 4) >> 16) & 0xFFFF */ -#define R_CKCORE_ADDRPLT_LO16 39 /* (GOT+G*4) & 0xffff */ -#define R_CKCORE_PCREL_JSR_IMM26BY2 40 /* disp ((S+A-P) >>1) & x3ffffff */ -#define R_CKCORE_TOFFSET_LO16 41 /* (S+A-BTEXT) & 0xffff */ -#define R_CKCORE_DOFFSET_LO16 42 /* (S+A-BTEXT) & 0xffff */ -#define R_CKCORE_PCREL_IMM18BY2 43 /* disp ((S+A-P) >>1) & 0x3ffff */ -#define R_CKCORE_DOFFSET_IMM18 44 /* disp (S+A-BDATA) & 0x3ffff */ -#define R_CKCORE_DOFFSET_IMM18BY2 45 /* disp ((S+A-BDATA)>>1) & 0x3ffff */ -#define R_CKCORE_DOFFSET_IMM18BY4 46 /* disp ((S+A-BDATA)>>2) & 0x3ffff */ -#define R_CKCORE_GOT_IMM18BY4 48 /* disp (G >> 2) */ -#define R_CKCORE_PLT_IMM18BY4 49 /* disp (G >> 2) */ -#define R_CKCORE_PCREL_IMM7BY4 50 /* disp ((S+A-P) >>2) & 0x7f */ -#define R_CKCORE_TLS_LE32 51 /* 32 bit offset to TLS block */ -#define R_CKCORE_TLS_IE32 52 -#define R_CKCORE_TLS_GD32 53 -#define R_CKCORE_TLS_LDM32 54 -#define R_CKCORE_TLS_LDO32 55 -#define R_CKCORE_TLS_DTPMOD32 56 -#define R_CKCORE_TLS_DTPOFF32 57 -#define R_CKCORE_TLS_TPOFF32 58 - -/* IA-64 specific declarations. */ - -/* Processor specific flags for the Ehdr e_flags field. */ -#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ -#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ -#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ - -/* Processor specific values for the Phdr p_type field. */ -#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ -#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ -#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) -#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) -#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) - -/* Processor specific flags for the Phdr p_flags field. */ -#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Shdr sh_type field. */ -#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ -#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ - -/* Processor specific flags for the Shdr sh_flags field. */ -#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ -#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ - -/* Processor specific values for the Dyn d_tag field. */ -#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) -#define DT_IA_64_NUM 1 - -/* IA-64 relocations. */ -#define R_IA64_NONE 0x00 /* none */ -#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ -#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ -#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ -#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ -#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ -#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ -#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ -#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ -#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ -#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ -#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ -#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ -#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ -#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ -#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ -#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ -#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ -#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ -#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ -#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ -#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ -#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ -#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ -#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ -#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ -#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ -#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ -#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ -#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ -#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ -#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ -#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ -#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ -#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ -#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ -#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ -#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ -#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ -#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ -#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ -#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ -#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ -#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ -#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ -#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ -#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ -#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ -#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ -#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ -#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ -#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ -#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ -#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ -#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ -#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ -#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ -#define R_IA64_COPY 0x84 /* copy relocation */ -#define R_IA64_SUB 0x85 /* Addend and symbol difference */ -#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ -#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ -#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ -#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ -#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ -#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ -#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ -#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ -#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ -#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ -#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ -#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ -#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ -#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ -#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ -#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ -#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ - -/* SH specific declarations */ - -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_SH_MACH_MASK 0x1f -#define EF_SH_UNKNOWN 0x0 -#define EF_SH1 0x1 -#define EF_SH2 0x2 -#define EF_SH3 0x3 -#define EF_SH_DSP 0x4 -#define EF_SH3_DSP 0x5 -#define EF_SH4AL_DSP 0x6 -#define EF_SH3E 0x8 -#define EF_SH4 0x9 -#define EF_SH2E 0xb -#define EF_SH4A 0xc -#define EF_SH2A 0xd -#define EF_SH4_NOFPU 0x10 -#define EF_SH4A_NOFPU 0x11 -#define EF_SH4_NOMMU_NOFPU 0x12 -#define EF_SH2A_NOFPU 0x13 -#define EF_SH3_NOMMU 0x14 -#define EF_SH2A_SH4_NOFPU 0x15 -#define EF_SH2A_SH3_NOFPU 0x16 -#define EF_SH2A_SH4 0x17 -#define EF_SH2A_SH3E 0x18 - -/* SH relocs. */ -#define R_SH_NONE 0 -#define R_SH_DIR32 1 -#define R_SH_REL32 2 -#define R_SH_DIR8WPN 3 -#define R_SH_IND12W 4 -#define R_SH_DIR8WPL 5 -#define R_SH_DIR8WPZ 6 -#define R_SH_DIR8BP 7 -#define R_SH_DIR8W 8 -#define R_SH_DIR8L 9 -#define R_SH_SWITCH16 25 -#define R_SH_SWITCH32 26 -#define R_SH_USES 27 -#define R_SH_COUNT 28 -#define R_SH_ALIGN 29 -#define R_SH_CODE 30 -#define R_SH_DATA 31 -#define R_SH_LABEL 32 -#define R_SH_SWITCH8 33 -#define R_SH_GNU_VTINHERIT 34 -#define R_SH_GNU_VTENTRY 35 -#define R_SH_TLS_GD_32 144 -#define R_SH_TLS_LD_32 145 -#define R_SH_TLS_LDO_32 146 -#define R_SH_TLS_IE_32 147 -#define R_SH_TLS_LE_32 148 -#define R_SH_TLS_DTPMOD32 149 -#define R_SH_TLS_DTPOFF32 150 -#define R_SH_TLS_TPOFF32 151 -#define R_SH_GOT32 160 -#define R_SH_PLT32 161 -#define R_SH_COPY 162 -#define R_SH_GLOB_DAT 163 -#define R_SH_JMP_SLOT 164 -#define R_SH_RELATIVE 165 -#define R_SH_GOTOFF 166 -#define R_SH_GOTPC 167 -/* Keep this the last entry. */ -#define R_SH_NUM 256 - -/* S/390 specific definitions. */ - -/* Valid values for the e_flags field. */ - -#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ - -/* Additional s390 relocs */ - -#define R_390_NONE 0 /* No reloc. */ -#define R_390_8 1 /* Direct 8 bit. */ -#define R_390_12 2 /* Direct 12 bit. */ -#define R_390_16 3 /* Direct 16 bit. */ -#define R_390_32 4 /* Direct 32 bit. */ -#define R_390_PC32 5 /* PC relative 32 bit. */ -#define R_390_GOT12 6 /* 12 bit GOT offset. */ -#define R_390_GOT32 7 /* 32 bit GOT offset. */ -#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ -#define R_390_COPY 9 /* Copy symbol at runtime. */ -#define R_390_GLOB_DAT 10 /* Create GOT entry. */ -#define R_390_JMP_SLOT 11 /* Create PLT entry. */ -#define R_390_RELATIVE 12 /* Adjust by program base. */ -#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ -#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ -#define R_390_GOT16 15 /* 16 bit GOT offset. */ -#define R_390_PC16 16 /* PC relative 16 bit. */ -#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ -#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ -#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ -#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ -#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ -#define R_390_64 22 /* Direct 64 bit. */ -#define R_390_PC64 23 /* PC relative 64 bit. */ -#define R_390_GOT64 24 /* 64 bit GOT offset. */ -#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ -#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ -#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ -#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ -#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ -#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ -#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ -#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ -#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ -#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ -#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ -#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ -#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ -#define R_390_TLS_GDCALL 38 /* Tag for function call in general - dynamic TLS code. */ -#define R_390_TLS_LDCALL 39 /* Tag for function call in local - dynamic TLS code. */ -#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic - thread local data. */ -#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic - thread local data. */ -#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic - thread local data in LE code. */ -#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS - block. */ -#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS - block. */ -#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ -#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ -#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS - block. */ -#define R_390_20 57 /* Direct 20 bit. */ -#define R_390_GOT20 58 /* 20 bit GOT offset. */ -#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ -#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS - block offset. */ -#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ -/* Keep this the last entry. */ -#define R_390_NUM 62 - - -/* CRIS relocations. */ -#define R_CRIS_NONE 0 -#define R_CRIS_8 1 -#define R_CRIS_16 2 -#define R_CRIS_32 3 -#define R_CRIS_8_PCREL 4 -#define R_CRIS_16_PCREL 5 -#define R_CRIS_32_PCREL 6 -#define R_CRIS_GNU_VTINHERIT 7 -#define R_CRIS_GNU_VTENTRY 8 -#define R_CRIS_COPY 9 -#define R_CRIS_GLOB_DAT 10 -#define R_CRIS_JUMP_SLOT 11 -#define R_CRIS_RELATIVE 12 -#define R_CRIS_16_GOT 13 -#define R_CRIS_32_GOT 14 -#define R_CRIS_16_GOTPLT 15 -#define R_CRIS_32_GOTPLT 16 -#define R_CRIS_32_GOTREL 17 -#define R_CRIS_32_PLT_GOTREL 18 -#define R_CRIS_32_PLT_PCREL 19 - -#define R_CRIS_NUM 20 - - -/* AMD x86-64 relocations. */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_COPY 5 /* Copy symbol at runtime */ -#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ -#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative - offset to GOT */ -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define R_X86_64_16 12 /* Direct 16 bit zero extended */ -#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ -#define R_X86_64_8 14 /* Direct 8 bit sign extended */ -#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ -#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ -#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ -#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ -#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset - to two GOT entries for GD symbol */ -#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset - to two GOT entries for LD symbol */ -#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ -#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset - to GOT entry for IE symbol */ -#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ -#define R_X86_64_PC64 24 /* PC relative 64 bit */ -#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ -#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative - offset to GOT */ -#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ -#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset - to GOT entry */ -#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ -#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ -#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset - to PLT entry */ -#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ -#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ -#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ -#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS - descriptor. */ -#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ -#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ -#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ - /* 39 Reserved was R_X86_64_PC32_BND */ - /* 40 Reserved was R_X86_64_PLT32_BND */ -#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative - offset to GOT entry without REX - prefix, relaxable. */ -#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative - offset to GOT entry with REX prefix, - relaxable. */ -#define R_X86_64_NUM 43 - -/* x86-64 sh_type values. */ -#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */ - - -/* AM33 relocations. */ -#define R_MN10300_NONE 0 /* No reloc. */ -#define R_MN10300_32 1 /* Direct 32 bit. */ -#define R_MN10300_16 2 /* Direct 16 bit. */ -#define R_MN10300_8 3 /* Direct 8 bit. */ -#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ -#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ -#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ -#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ -#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ -#define R_MN10300_24 9 /* Direct 24 bit. */ -#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ -#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ -#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ -#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ -#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ -#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ -#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ -#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ -#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ -#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ -#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ -#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ -#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ -#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ -#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ -#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ -#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ -#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block - offset. */ -#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block - offset. */ -#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS - block. */ -#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ -#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ -#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ -#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed - by linker relaxation. */ -#define R_MN10300_ALIGN 34 /* Alignment requirement for linker - relaxation. */ -#define R_MN10300_NUM 35 - - -/* M32R relocs. */ -#define R_M32R_NONE 0 /* No reloc. */ -#define R_M32R_16 1 /* Direct 16 bit. */ -#define R_M32R_32 2 /* Direct 32 bit. */ -#define R_M32R_24 3 /* Direct 24 bit. */ -#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ -#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ -#define R_M32R_LO16 9 /* Low 16 bit. */ -#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ -#define R_M32R_GNU_VTINHERIT 11 -#define R_M32R_GNU_VTENTRY 12 -/* M32R relocs use SHT_RELA. */ -#define R_M32R_16_RELA 33 /* Direct 16 bit. */ -#define R_M32R_32_RELA 34 /* Direct 32 bit. */ -#define R_M32R_24_RELA 35 /* Direct 24 bit. */ -#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ -#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ -#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ -#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ -#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ -#define R_M32R_LO16_RELA 41 /* Low 16 bit */ -#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ -#define R_M32R_RELA_GNU_VTINHERIT 43 -#define R_M32R_RELA_GNU_VTENTRY 44 -#define R_M32R_REL32 45 /* PC relative 32 bit. */ - -#define R_M32R_GOT24 48 /* 24 bit GOT entry */ -#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ -#define R_M32R_COPY 50 /* Copy symbol at runtime */ -#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ -#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ -#define R_M32R_RELATIVE 53 /* Adjust by program base */ -#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ -#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ -#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned - low */ -#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed - low */ -#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ -#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to - GOT with unsigned low */ -#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to - GOT with signed low */ -#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to - GOT */ -#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT - with unsigned low */ -#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT - with signed low */ -#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ -#define R_M32R_NUM 256 /* Keep this the last entry. */ - -/* MicroBlaze relocations */ -#define R_MICROBLAZE_NONE 0 /* No reloc. */ -#define R_MICROBLAZE_32 1 /* Direct 32 bit. */ -#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */ -#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */ -#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */ -#define R_MICROBLAZE_64 5 /* Direct 64 bit. */ -#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */ -#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */ -#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */ -#define R_MICROBLAZE_64_NONE 9 /* No reloc. */ -#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */ -#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */ -#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */ -#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */ -#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */ -#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */ -#define R_MICROBLAZE_REL 16 /* Adjust by program base. */ -#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */ -#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */ -#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */ -#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */ -#define R_MICROBLAZE_COPY 21 /* Runtime copy. */ -#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */ -#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */ -#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */ -#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */ -#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */ -#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */ -#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */ -#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */ - -/* Legal values for d_tag (dynamic entry type). */ -#define DT_NIOS2_GP 0x70000002 /* Address of _gp. */ - -/* Nios II relocations. */ -#define R_NIOS2_NONE 0 /* No reloc. */ -#define R_NIOS2_S16 1 /* Direct signed 16 bit. */ -#define R_NIOS2_U16 2 /* Direct unsigned 16 bit. */ -#define R_NIOS2_PCREL16 3 /* PC relative 16 bit. */ -#define R_NIOS2_CALL26 4 /* Direct call. */ -#define R_NIOS2_IMM5 5 /* 5 bit constant expression. */ -#define R_NIOS2_CACHE_OPX 6 /* 5 bit expression, shift 22. */ -#define R_NIOS2_IMM6 7 /* 6 bit constant expression. */ -#define R_NIOS2_IMM8 8 /* 8 bit constant expression. */ -#define R_NIOS2_HI16 9 /* High 16 bit. */ -#define R_NIOS2_LO16 10 /* Low 16 bit. */ -#define R_NIOS2_HIADJ16 11 /* High 16 bit, adjusted. */ -#define R_NIOS2_BFD_RELOC_32 12 /* 32 bit symbol value + addend. */ -#define R_NIOS2_BFD_RELOC_16 13 /* 16 bit symbol value + addend. */ -#define R_NIOS2_BFD_RELOC_8 14 /* 8 bit symbol value + addend. */ -#define R_NIOS2_GPREL 15 /* 16 bit GP pointer offset. */ -#define R_NIOS2_GNU_VTINHERIT 16 /* GNU C++ vtable hierarchy. */ -#define R_NIOS2_GNU_VTENTRY 17 /* GNU C++ vtable member usage. */ -#define R_NIOS2_UJMP 18 /* Unconditional branch. */ -#define R_NIOS2_CJMP 19 /* Conditional branch. */ -#define R_NIOS2_CALLR 20 /* Indirect call through register. */ -#define R_NIOS2_ALIGN 21 /* Alignment requirement for - linker relaxation. */ -#define R_NIOS2_GOT16 22 /* 16 bit GOT entry. */ -#define R_NIOS2_CALL16 23 /* 16 bit GOT entry for function. */ -#define R_NIOS2_GOTOFF_LO 24 /* %lo of offset to GOT pointer. */ -#define R_NIOS2_GOTOFF_HA 25 /* %hiadj of offset to GOT pointer. */ -#define R_NIOS2_PCREL_LO 26 /* %lo of PC relative offset. */ -#define R_NIOS2_PCREL_HA 27 /* %hiadj of PC relative offset. */ -#define R_NIOS2_TLS_GD16 28 /* 16 bit GOT offset for TLS GD. */ -#define R_NIOS2_TLS_LDM16 29 /* 16 bit GOT offset for TLS LDM. */ -#define R_NIOS2_TLS_LDO16 30 /* 16 bit module relative offset. */ -#define R_NIOS2_TLS_IE16 31 /* 16 bit GOT offset for TLS IE. */ -#define R_NIOS2_TLS_LE16 32 /* 16 bit LE TP-relative offset. */ -#define R_NIOS2_TLS_DTPMOD 33 /* Module number. */ -#define R_NIOS2_TLS_DTPREL 34 /* Module-relative offset. */ -#define R_NIOS2_TLS_TPREL 35 /* TP-relative offset. */ -#define R_NIOS2_COPY 36 /* Copy symbol at runtime. */ -#define R_NIOS2_GLOB_DAT 37 /* Create GOT entry. */ -#define R_NIOS2_JUMP_SLOT 38 /* Create PLT entry. */ -#define R_NIOS2_RELATIVE 39 /* Adjust by program base. */ -#define R_NIOS2_GOTOFF 40 /* 16 bit offset to GOT pointer. */ -#define R_NIOS2_CALL26_NOAT 41 /* Direct call in .noat section. */ -#define R_NIOS2_GOT_LO 42 /* %lo() of GOT entry. */ -#define R_NIOS2_GOT_HA 43 /* %hiadj() of GOT entry. */ -#define R_NIOS2_CALL_LO 44 /* %lo() of function GOT entry. */ -#define R_NIOS2_CALL_HA 45 /* %hiadj() of function GOT entry. */ - -/* TILEPro relocations. */ -#define R_TILEPRO_NONE 0 /* No reloc */ -#define R_TILEPRO_32 1 /* Direct 32 bit */ -#define R_TILEPRO_16 2 /* Direct 16 bit */ -#define R_TILEPRO_8 3 /* Direct 8 bit */ -#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ -#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ -#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ -#define R_TILEPRO_LO16 7 /* Low 16 bit */ -#define R_TILEPRO_HI16 8 /* High 16 bit */ -#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ -#define R_TILEPRO_COPY 10 /* Copy relocation */ -#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ -#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ -#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ -#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ -#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ -#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ -#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ -#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ -#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ -#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ -#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ -#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ -#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ -#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ -#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ -#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ -#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ -#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ -#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ -#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ -#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ -#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ -#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ -#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ -#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ -#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ -#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ -#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ -#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ -/* Relocs 56-59 are currently not defined. */ -#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ -#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ -#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ -#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ -#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ -#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ -#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ -#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ - -#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEPRO_NUM 130 - - -/* TILE-Gx relocations. */ -#define R_TILEGX_NONE 0 /* No reloc */ -#define R_TILEGX_64 1 /* Direct 64 bit */ -#define R_TILEGX_32 2 /* Direct 32 bit */ -#define R_TILEGX_16 3 /* Direct 16 bit */ -#define R_TILEGX_8 4 /* Direct 8 bit */ -#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ -#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ -#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ -#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ -#define R_TILEGX_HW0 9 /* hword 0 16-bit */ -#define R_TILEGX_HW1 10 /* hword 1 16-bit */ -#define R_TILEGX_HW2 11 /* hword 2 16-bit */ -#define R_TILEGX_HW3 12 /* hword 3 16-bit */ -#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ -#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ -#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ -#define R_TILEGX_COPY 16 /* Copy relocation */ -#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ -#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ -#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ -#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ -#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ -#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ -#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ -#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ -#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ -#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ -#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ -#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ -#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ -#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ -#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ -#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ -#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ -#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ -#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ -#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ -#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ -#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ -#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ -#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ -#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ -#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ -#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ -#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ -#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ -#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ -#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ -#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ -/* Relocs 90-91 are currently not defined. */ -#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ -#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ -#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ -#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ -#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ -#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ -#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ -/* Relocs 104-105 are currently not defined. */ -#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ -#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ -#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ -#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ -#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ -#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ -#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ -#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ -#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ -#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ - -#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ -#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ - -#define R_TILEGX_NUM 130 - -/* RISC-V ELF Flags */ -#define EF_RISCV_RVC 0x0001 -#define EF_RISCV_FLOAT_ABI 0x0006 -#define EF_RISCV_FLOAT_ABI_SOFT 0x0000 -#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002 -#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004 -#define EF_RISCV_FLOAT_ABI_QUAD 0x0006 - -/* RISC-V relocations. */ -#define R_RISCV_NONE 0 -#define R_RISCV_32 1 -#define R_RISCV_64 2 -#define R_RISCV_RELATIVE 3 -#define R_RISCV_COPY 4 -#define R_RISCV_JUMP_SLOT 5 -#define R_RISCV_TLS_DTPMOD32 6 -#define R_RISCV_TLS_DTPMOD64 7 -#define R_RISCV_TLS_DTPREL32 8 -#define R_RISCV_TLS_DTPREL64 9 -#define R_RISCV_TLS_TPREL32 10 -#define R_RISCV_TLS_TPREL64 11 -#define R_RISCV_BRANCH 16 -#define R_RISCV_JAL 17 -#define R_RISCV_CALL 18 -#define R_RISCV_CALL_PLT 19 -#define R_RISCV_GOT_HI20 20 -#define R_RISCV_TLS_GOT_HI20 21 -#define R_RISCV_TLS_GD_HI20 22 -#define R_RISCV_PCREL_HI20 23 -#define R_RISCV_PCREL_LO12_I 24 -#define R_RISCV_PCREL_LO12_S 25 -#define R_RISCV_HI20 26 -#define R_RISCV_LO12_I 27 -#define R_RISCV_LO12_S 28 -#define R_RISCV_TPREL_HI20 29 -#define R_RISCV_TPREL_LO12_I 30 -#define R_RISCV_TPREL_LO12_S 31 -#define R_RISCV_TPREL_ADD 32 -#define R_RISCV_ADD8 33 -#define R_RISCV_ADD16 34 -#define R_RISCV_ADD32 35 -#define R_RISCV_ADD64 36 -#define R_RISCV_SUB8 37 -#define R_RISCV_SUB16 38 -#define R_RISCV_SUB32 39 -#define R_RISCV_SUB64 40 -#define R_RISCV_GNU_VTINHERIT 41 -#define R_RISCV_GNU_VTENTRY 42 -#define R_RISCV_ALIGN 43 -#define R_RISCV_RVC_BRANCH 44 -#define R_RISCV_RVC_JUMP 45 -#define R_RISCV_RVC_LUI 46 -#define R_RISCV_GPREL_I 47 -#define R_RISCV_GPREL_S 48 -#define R_RISCV_TPREL_I 49 -#define R_RISCV_TPREL_S 50 -#define R_RISCV_RELAX 51 -#define R_RISCV_SUB6 52 -#define R_RISCV_SET6 53 -#define R_RISCV_SET8 54 -#define R_RISCV_SET16 55 -#define R_RISCV_SET32 56 -#define R_RISCV_32_PCREL 57 - -#define R_RISCV_NUM 58 - -/* BPF specific declarations. */ - -#define R_BPF_NONE 0 /* No reloc */ -#define R_BPF_64_64 1 -#define R_BPF_64_32 10 - -/* Imagination Meta specific relocations. */ - -#define R_METAG_HIADDR16 0 -#define R_METAG_LOADDR16 1 -#define R_METAG_ADDR32 2 /* 32bit absolute address */ -#define R_METAG_NONE 3 /* No reloc */ -#define R_METAG_RELBRANCH 4 -#define R_METAG_GETSETOFF 5 - -/* Backward compatability */ -#define R_METAG_REG32OP1 6 -#define R_METAG_REG32OP2 7 -#define R_METAG_REG32OP3 8 -#define R_METAG_REG16OP1 9 -#define R_METAG_REG16OP2 10 -#define R_METAG_REG16OP3 11 -#define R_METAG_REG32OP4 12 - -#define R_METAG_HIOG 13 -#define R_METAG_LOOG 14 - -#define R_METAG_REL8 15 -#define R_METAG_REL16 16 - -/* GNU */ -#define R_METAG_GNU_VTINHERIT 30 -#define R_METAG_GNU_VTENTRY 31 - -/* PIC relocations */ -#define R_METAG_HI16_GOTOFF 32 -#define R_METAG_LO16_GOTOFF 33 -#define R_METAG_GETSET_GOTOFF 34 -#define R_METAG_GETSET_GOT 35 -#define R_METAG_HI16_GOTPC 36 -#define R_METAG_LO16_GOTPC 37 -#define R_METAG_HI16_PLT 38 -#define R_METAG_LO16_PLT 39 -#define R_METAG_RELBRANCH_PLT 40 -#define R_METAG_GOTOFF 41 -#define R_METAG_PLT 42 -#define R_METAG_COPY 43 -#define R_METAG_JMP_SLOT 44 -#define R_METAG_RELATIVE 45 -#define R_METAG_GLOB_DAT 46 - -/* TLS relocations */ -#define R_METAG_TLS_GD 47 -#define R_METAG_TLS_LDM 48 -#define R_METAG_TLS_LDO_HI16 49 -#define R_METAG_TLS_LDO_LO16 50 -#define R_METAG_TLS_LDO 51 -#define R_METAG_TLS_IE 52 -#define R_METAG_TLS_IENONPIC 53 -#define R_METAG_TLS_IENONPIC_HI16 54 -#define R_METAG_TLS_IENONPIC_LO16 55 -#define R_METAG_TLS_TPOFF 56 -#define R_METAG_TLS_DTPMOD 57 -#define R_METAG_TLS_DTPOFF 58 -#define R_METAG_TLS_LE 59 -#define R_METAG_TLS_LE_HI16 60 -#define R_METAG_TLS_LE_LO16 61 - -/* NDS32 relocations. */ -#define R_NDS32_NONE 0 -#define R_NDS32_32_RELA 20 -#define R_NDS32_COPY 39 -#define R_NDS32_GLOB_DAT 40 -#define R_NDS32_JMP_SLOT 41 -#define R_NDS32_RELATIVE 42 -#define R_NDS32_TLS_TPOFF 102 -#define R_NDS32_TLS_DESC 119 - -#ifdef __cplusplus -} -#endif - -#endif /* elf.h */ From 55cee0127efe6453a7efda2dfc04b4ee93c0df57 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 20 Apr 2022 00:09:00 -0400 Subject: [PATCH 157/478] ios: Don't start upload thread from background. It is not safe to start the upload thread when in the background (due to the potential for flocked files in shared containers). Bug: 1317812 Change-Id: Ie476c2ccbc7232bc9e1a30a7a497128a4248c39e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3595621 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/ios_handler/in_process_handler.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index f37b4d50cf..f13b140d58 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -273,7 +273,14 @@ void InProcessHandler::StartProcessingPendingReports() { return; upload_thread_enabled_ = true; - UpdatePruneAndUploadThreads(true); + + // This may be a no-op if IsApplicationActive is false, as it is not safe to + // start the upload thread when in the background (due to the potential for + // flocked files in shared containers). + // TODO(crbug.com/crashpad/400): Consider moving prune and upload thread to + // BackgroundTasks and/or NSURLSession. This might allow uploads to continue + // in the background. + UpdatePruneAndUploadThreads(system_data_.IsApplicationActive()); } void InProcessHandler::UpdatePruneAndUploadThreads(bool active) { From dfb3b596607ab5e0707de3376fe70e1901173319 Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Thu, 5 May 2022 15:19:17 -0700 Subject: [PATCH 158/478] In C++20, atomics are value-initialized by default. ATOMIC_FLAG_INIT is thus deprecated. Feature-test for this. Bug: chromium:1284275 Change-Id: I000d9d8ba5248bf72390b25b2165094faf5aa3db Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3629949 Commit-Queue: Mark Mentovai Reviewed-by: Mark Mentovai --- handler/handler_main.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 48ef8b6530..c6ef769337 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -287,7 +287,12 @@ bool AddKeyValueToMap(std::map* map, // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after // something else logs an exit event. void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { +#if !defined(__cpp_lib_atomic_value_initialization) || \ + __cpp_lib_atomic_value_initialization < 201911L static std::atomic_flag metrics_exit_recorded = ATOMIC_FLAG_INIT; +#else + static std::atomic_flag metrics_exit_recorded; +#endif if (!metrics_exit_recorded.test_and_set()) { Metrics::HandlerLifetimeMilestone(milestone); } From 34a090b5730fef3ee8da0570c7d2ce79ec78ba3f Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 10 May 2022 10:44:56 -0400 Subject: [PATCH 159/478] ios: Capture more exceptionReason in exception processor. This brings Crashpad in line with what Breakpad captures. Change-Id: I8ce2d81fc9cb150dc9817034fac3516f27f5661b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3611069 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- client/ios_handler/exception_processor.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ios_handler/exception_processor.mm b/client/ios_handler/exception_processor.mm index 5aa4c78d53..e276554499 100644 --- a/client/ios_handler/exception_processor.mm +++ b/client/ios_handler/exception_processor.mm @@ -147,7 +147,7 @@ static void SetNSExceptionAnnotations(NSException* exception, @try { reason = base::SysNSStringToUTF8(exception.reason); - static StringAnnotation<512> reasonKey("exceptionReason"); + static StringAnnotation<1024> reasonKey("exceptionReason"); reasonKey.Set(reason); } @catch (id reason_exception) { LOG(ERROR) << "Unable to read uncaught Objective-C exception reason."; @@ -155,7 +155,7 @@ static void SetNSExceptionAnnotations(NSException* exception, @try { if (exception.userInfo) { - static StringAnnotation<512> userInfoKey("exceptionUserInfo"); + static StringAnnotation<1024> userInfoKey("exceptionUserInfo"); userInfoKey.Set(base::SysNSStringToUTF8( [NSString stringWithFormat:@"%@", exception.userInfo])); } From 94242690d57be5df0dd60cc51bc2f41bb451ff89 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 10 May 2022 10:41:04 -0400 Subject: [PATCH 160/478] ios: Check dyld_image_info->imageFilePath for nullptr. It seems on iOS 14, sometimes this path can be empty. Passing nullptr to strlen will crash. Also fixes an incorrect file path length for the dyldPath. Bug: 1323905 Change-Id: Idf1ef9e0165853a5d57d272896a40bf0b30a3368 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3637717 Reviewed-by: Joshua Peraza Commit-Queue: Justin Cohen --- .../in_process_intermediate_dump_handler.cc | 17 +++++++--- ...ess_snapshot_ios_intermediate_dump_test.cc | 33 +++++++++++-------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index 88d5eb0a6e..2869c2174f 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -963,10 +963,12 @@ void InProcessIntermediateDumpHandler::WriteModuleInfo( return; } - WriteProperty(writer, - IntermediateDumpKey::kName, - image->imageFilePath, - strlen(image->imageFilePath)); + if (image->imageFilePath) { + WriteProperty(writer, + IntermediateDumpKey::kName, + image->imageFilePath, + strlen(image->imageFilePath)); + } uint64_t address = FromPointerCast(image->imageLoadAddress); WriteProperty(writer, IntermediateDumpKey::kAddress, &address); WriteProperty( @@ -976,7 +978,12 @@ void InProcessIntermediateDumpHandler::WriteModuleInfo( { IOSIntermediateDumpWriter::ScopedArrayMap modules(writer); - WriteProperty(writer, IntermediateDumpKey::kName, image_infos->dyldPath); + if (image_infos->dyldPath) { + WriteProperty(writer, + IntermediateDumpKey::kName, + image_infos->dyldPath, + strlen(image_infos->dyldPath)); + } uint64_t address = FromPointerCast(image_infos->dyldImageLoadAddress); WriteProperty(writer, IntermediateDumpKey::kAddress, &address); diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 5f56082eb1..44a7b775b1 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -198,14 +198,16 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } } - void WriteModules(IOSIntermediateDumpWriter* writer) { + void WriteModules(IOSIntermediateDumpWriter* writer, bool has_module_path) { IOSIntermediateDumpWriter::ScopedArray moduleArray(writer, Key::kModules); for (uint32_t image_index = 0; image_index < 2; ++image_index) { IOSIntermediateDumpWriter::ScopedArrayMap modules(writer); - constexpr char image_file[] = "/path/to/module"; - EXPECT_TRUE( - writer->AddProperty(Key::kName, image_file, strlen(image_file))); + if (has_module_path) { + constexpr char image_file[] = "/path/to/module"; + EXPECT_TRUE( + writer->AddProperty(Key::kName, image_file, strlen(image_file))); + } uint64_t address = 0; uint64_t vmsize = 1; @@ -241,12 +243,16 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } } - void ExpectModules(const std::vector& modules) { + void ExpectModules(const std::vector& modules, + bool expect_module_path) { for (auto module : modules) { EXPECT_EQ(module->GetModuleType(), ModuleSnapshot::kModuleTypeSharedLibrary); - EXPECT_STREQ(module->Name().c_str(), "/path/to/module"); - EXPECT_STREQ(module->DebugFileName().c_str(), "module"); + + if (expect_module_path) { + EXPECT_STREQ(module->Name().c_str(), "/path/to/module"); + EXPECT_STREQ(module->DebugFileName().c_str(), "module"); + } UUID uuid; uint32_t age; module->UUIDAndAge(&uuid, &age); @@ -424,7 +430,8 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { EXPECT_STREQ(daylight_name.c_str(), "Daylight"); } - void ExpectSnapshot(const ProcessSnapshot& snapshot) { + void ExpectSnapshot(const ProcessSnapshot& snapshot, + bool expect_module_path) { EXPECT_EQ(snapshot.ProcessID(), 2); EXPECT_EQ(snapshot.ParentProcessID(), 1); @@ -447,7 +454,7 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { ExpectSystem(*snapshot.System()); ExpectThreads(snapshot.Threads()); - ExpectModules(snapshot.Modules()); + ExpectModules(snapshot.Modules(), expect_module_path); ExpectMachException(*snapshot.Exception()); } @@ -626,14 +633,14 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, ShortContext) { WriteSystemInfo(writer()); WriteProcessInfo(writer()); WriteThreads(writer()); - WriteModules(writer()); + WriteModules(writer(), /*has_module_path=*/false); WriteMachException(writer(), true /* short_context=true*/); } ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); EXPECT_TRUE(DumpSnapshot(process_snapshot)); - ExpectSnapshot(process_snapshot); + ExpectSnapshot(process_snapshot, /*expect_module_path=*/false); } TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) { @@ -644,14 +651,14 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) { WriteSystemInfo(writer()); WriteProcessInfo(writer()); WriteThreads(writer()); - WriteModules(writer()); + WriteModules(writer(), /*has_module_path=*/true); WriteMachException(writer()); } ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); EXPECT_TRUE(DumpSnapshot(process_snapshot)); - ExpectSnapshot(process_snapshot); + ExpectSnapshot(process_snapshot, /*expect_module_path=*/true); } TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FuzzTestCases) { From 4581a355b17e9deae20447cec88c315210f50b7a Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Tue, 10 May 2022 12:34:01 -0400 Subject: [PATCH 161/478] ios: Limit depth of intermediate dump parser. Limit the parser stack to 10 to prevent malformed intermediate dumps from causing a stack overflow. Bug: 1321382 Change-Id: I880e80de585b0fb18f0c383102b9227d6ffbfa76 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3637719 Commit-Queue: Justin Cohen Reviewed-by: Joshua Peraza --- snapshot/BUILD.gn | 1 + ...ocess_snapshot_ios_intermediate_dump_test.cc | 5 +++++ snapshot/ios/testdata/crash-6605504629637120 | Bin 0 -> 42751 bytes util/ios/ios_intermediate_dump_reader.cc | 6 ++++++ 4 files changed, 12 insertions(+) create mode 100644 snapshot/ios/testdata/crash-6605504629637120 diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index ea2412a0bf..b331598283 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -492,6 +492,7 @@ bundle_data("snapshot_test_ios_data") { sources = [ "ios/testdata/crash-1fa088dda0adb41459d063078a0f384a0bb8eefa", "ios/testdata/crash-5726011582644224", + "ios/testdata/crash-6605504629637120", ] outputs = [ "{{bundle_resources_dir}}/crashpad_test_data/" + diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 44a7b775b1..1a994bdb83 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -679,6 +679,11 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FuzzTestCases) { map = process_snapshot2.AnnotationsSimpleMap(); ASSERT_TRUE(map.find("crashpad_intermediate_dump_incomplete") != map.end()); EXPECT_EQ(map["crashpad_intermediate_dump_incomplete"], "yes"); + + fuzz_path = TestPaths::TestDataRoot().Append( + FILE_PATH_LITERAL("snapshot/ios/testdata/crash-6605504629637120")); + crashpad::internal::ProcessSnapshotIOSIntermediateDump process_snapshot3; + EXPECT_FALSE(process_snapshot3.InitializeWithFilePath(fuzz_path, {})); } } // namespace diff --git a/snapshot/ios/testdata/crash-6605504629637120 b/snapshot/ios/testdata/crash-6605504629637120 new file mode 100644 index 0000000000000000000000000000000000000000..1e041d9021eda5d220ac847f7dbe4a6b8b813e19 GIT binary patch literal 42751 zcmeI3;c=rd5QR;cNmu!kQqsxIHF6DHbyon#B38&k8*CzEX8AnhAs{5s)7z)jlk?sU zL;ulr{l{(mj>pgUaGb8m^}@B!(zUE!(oQ!wU2H0=_9f@x+S~d?^re!}OMA@DJQ(aeyH(L^uEsz`#8ZP<>QC=B+3misxSO?$%f^9>$xD zSEfXLob7^mZnH-WgyT$vjY)go!++1cn;M`0jy=uK>3J}f49t`{4`CVFc*aCJ^Z47$ zXjy_MgfAu$3J<^l9<)?m_y*tL8>=ee06YK#co2SaKr9do!~(G}x;-2A4N8GhoLDK; z+r%4QAz??ZM7>6S@Ovl!_#1!NiyxfyR`L3#*EuR)P*^eJAq-Zv(wN)9r+QmFI+S{R zs5^lQZih4ujy-JkOE9=G95Ed0#}%xCRj`VMm~a3dfB`(fw$cSWdVn6F2j~HMu-J8I zBAVz-6V=;{zFuNwPkyJ(c~J&chrCw#+>0xE>7J*IFagc-uw46!i_6d9jt zL~+-wSWEA`?yQpH_CsymGi;l6UbPW7V)3d+6V0rFCEtSwVBnAk>5QZEuU^~W{H0ex z0Na^sdm$MJ1B^5>|OZVWojd zA8ia)wbGc|!6*LxTliE71$%H>max%*@hk!Y55NE(v{YXB2H)VDtEKJ6B975!w1ork z01V&(CjV$zF=K#1H078VT+It=SI6=C{FGlyJd!91JWR36fw_}15 zSL#USvoG^WHKMo)XvYcKTGmc`12x>A&#i}0mkpTis+&*}v3Ar_0y^y&Qcs5JwZuLV z8h{40(*Ur366>7_;Z^gUeG8wRAVcOS$sCO*CY{rA2NNK&G+)x&ti}Gwv3l%0w?CSb z&(#mEFY9tJ>qpJ9HR`1$%>!E>SoE=Tak8P=C+w9}C3(%Kx)bW<+ImQmixY$BUfn~h z7X$TLy84)$c6oJ(3NzaF3{J@@W1(&wXnG{aV#a5)U|)u(4=g?`$=f!%x$*E}2>*Yd jJVmm)s_A9*21ShGcY5<-{&eH#t-tmE{`~rT>u>)7l)8-t literal 0 HcmV?d00001 diff --git a/util/ios/ios_intermediate_dump_reader.cc b/util/ios/ios_intermediate_dump_reader.cc index 022133bce7..d9610f656f 100644 --- a/util/ios/ios_intermediate_dump_reader.cc +++ b/util/ios/ios_intermediate_dump_reader.cc @@ -70,6 +70,12 @@ bool IOSIntermediateDumpReader::Parse(FileReaderInterface* reader, } while (reader->ReadExactly(&command, sizeof(Command))) { + constexpr int kMaxStackDepth = 10; + if (stack.size() > kMaxStackDepth) { + LOG(ERROR) << "Unexpected depth of intermediate dump data."; + return false; + } + IOSIntermediateDumpObject* parent = stack.top(); switch (command) { case Command::kMapStart: { From df2cb4c93bb512650f2bff43f69ae2bf18d929d3 Mon Sep 17 00:00:00 2001 From: Andrei Malashkin Date: Thu, 12 May 2022 05:09:25 -0700 Subject: [PATCH 162/478] CMake: try to use jwasm for mingw build, if possible (#63) --- CMakeLists.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b13b78faea..b6e2e6d5ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,22 @@ endfunction() if(WIN32) enable_language(ASM_MASM) + if(MINGW) + find_program(JWASM_FOUND jwasm) + if (JWASM_FOUND) + set(CMAKE_ASM_MASM_COMPILER ${JWASM_FOUND}) + execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE COMPILER_VERSION_OUTPUT) + if (COMPILER_VERSION_OUTPUT) + if (COMPILER_VERSION_OUTPUT MATCHES "x86_64") + set(JWASM_FLAGS -win64) + else() + set(JWASM_FLAGS -coff) + endif() + endif() + set(CMAKE_ASM_MASM_FLAGS ${CMAKE_ASM_MASM_FLAGS} ${JWASM_FLAGS}) + endif(JWASM_FOUND) + if(NOT CMAKE_ASM_MASM_COMPILER OR CMAKE_ASM_MASM_COMPILER STREQUAL "ml" OR CMAKE_ASM_MASM_COMPILER STREQUAL "ml64") message(WARNING "No custom ASM_MASM compiler defined via 'CMAKE_ASM_MASM_COMPILER'. Trying to use UASM...") set(CMAKE_ASM_MASM_COMPILER "uasm") @@ -60,7 +75,7 @@ if(WIN32) if(NOT CMAKE_ASM_MASM_FLAGS) set(CMAKE_ASM_MASM_FLAGS "-win64 -10") #use default compatibility flags endif() - endif() + endif(MINGW) else() enable_language(ASM) endif() From a5b7e504c6fdba0e32558fe541174100e2ee94bb Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Sat, 14 May 2022 22:40:02 -0700 Subject: [PATCH 163/478] Thread snapshots on Windows can have varying size In a future CL we will make use of InitializeContext2 which can produce contexts of varying sizes - this makes the existing use of a union for wow/x64 contexts no longer feasible. The context union in process_reader_win is replaced with a (moveable, copyable) helper struct which currently only knows how to allocate the replaced WOW or CONTEXT sized unions. As this field is no longer a member of the Thread struct it cannot be passed into other functions as a reference, so instead a pointer is used in these functions. Bug: 1250098 Change-Id: Ied3fe971c0073bbdafc071217e1bb0f72350bb4e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3538668 Commit-Queue: Alex Gough Reviewed-by: Joshua Peraza --- snapshot/win/cpu_context_win.cc | 148 ++++++++++++------------ snapshot/win/cpu_context_win.h | 9 +- snapshot/win/cpu_context_win_test.cc | 6 +- snapshot/win/exception_snapshot_win.cc | 15 ++- snapshot/win/exception_snapshot_win.h | 2 +- snapshot/win/process_reader_win.cc | 49 ++++++-- snapshot/win/process_reader_win.h | 34 +++++- snapshot/win/process_reader_win_test.cc | 3 +- snapshot/win/thread_snapshot_win.cc | 12 +- 9 files changed, 165 insertions(+), 113 deletions(-) diff --git a/snapshot/win/cpu_context_win.cc b/snapshot/win/cpu_context_win.cc index db2e80362c..0d7783829a 100644 --- a/snapshot/win/cpu_context_win.cc +++ b/snapshot/win/cpu_context_win.cc @@ -36,12 +36,12 @@ static_assert(sizeof(CPUContextX86::Fsave) == #endif // ARCH_CPU_X86 template -bool HasContextPart(const T& context, uint32_t bits) { - return (context.ContextFlags & bits) == bits; +bool HasContextPart(const T* context, uint32_t bits) { + return (context->ContextFlags & bits) == bits; } template -void CommonInitializeX86Context(const T& context, CPUContextX86* out) { +void CommonInitializeX86Context(const T* context, CPUContextX86* out) { // This function assumes that the WOW64_CONTEXT_* and x86 CONTEXT_* values // for ContextFlags are identical. This can be tested when targeting 32-bit // x86. @@ -72,54 +72,54 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) { << "non-x86 context"; if (HasContextPart(context, WOW64_CONTEXT_CONTROL)) { - out->ebp = context.Ebp; - out->eip = context.Eip; - out->cs = static_cast(context.SegCs); - out->eflags = context.EFlags; - out->esp = context.Esp; - out->ss = static_cast(context.SegSs); + out->ebp = context->Ebp; + out->eip = context->Eip; + out->cs = static_cast(context->SegCs); + out->eflags = context->EFlags; + out->esp = context->Esp; + out->ss = static_cast(context->SegSs); } if (HasContextPart(context, WOW64_CONTEXT_INTEGER)) { - out->eax = context.Eax; - out->ebx = context.Ebx; - out->ecx = context.Ecx; - out->edx = context.Edx; - out->edi = context.Edi; - out->esi = context.Esi; + out->eax = context->Eax; + out->ebx = context->Ebx; + out->ecx = context->Ecx; + out->edx = context->Edx; + out->edi = context->Edi; + out->esi = context->Esi; } if (HasContextPart(context, WOW64_CONTEXT_SEGMENTS)) { - out->ds = static_cast(context.SegDs); - out->es = static_cast(context.SegEs); - out->fs = static_cast(context.SegFs); - out->gs = static_cast(context.SegGs); + out->ds = static_cast(context->SegDs); + out->es = static_cast(context->SegEs); + out->fs = static_cast(context->SegFs); + out->gs = static_cast(context->SegGs); } if (HasContextPart(context, WOW64_CONTEXT_DEBUG_REGISTERS)) { - out->dr0 = context.Dr0; - out->dr1 = context.Dr1; - out->dr2 = context.Dr2; - out->dr3 = context.Dr3; + out->dr0 = context->Dr0; + out->dr1 = context->Dr1; + out->dr2 = context->Dr2; + out->dr3 = context->Dr3; // DR4 and DR5 are obsolete synonyms for DR6 and DR7, see // https://en.wikipedia.org/wiki/X86_debug_register. - out->dr4 = context.Dr6; - out->dr5 = context.Dr7; + out->dr4 = context->Dr6; + out->dr5 = context->Dr7; - out->dr6 = context.Dr6; - out->dr7 = context.Dr7; + out->dr6 = context->Dr6; + out->dr7 = context->Dr7; } if (HasContextPart(context, WOW64_CONTEXT_EXTENDED_REGISTERS)) { - static_assert(sizeof(out->fxsave) == sizeof(context.ExtendedRegisters), + static_assert(sizeof(out->fxsave) == sizeof(context->ExtendedRegisters), "fxsave types must be equivalent"); - memcpy(&out->fxsave, &context.ExtendedRegisters, sizeof(out->fxsave)); + memcpy(&out->fxsave, &context->ExtendedRegisters, sizeof(out->fxsave)); } else if (HasContextPart(context, WOW64_CONTEXT_FLOATING_POINT)) { // The static_assert that validates this cast can’t be here because it // relies on field names that vary based on the template parameter. CPUContextX86::FsaveToFxsave( - *reinterpret_cast(&context.FloatSave), + *reinterpret_cast(&context->FloatSave), &out->fxsave); } } @@ -128,101 +128,101 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) { #if defined(ARCH_CPU_X86) -void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) { +void InitializeX86Context(const CONTEXT* context, CPUContextX86* out) { CommonInitializeX86Context(context, out); } #elif defined(ARCH_CPU_X86_64) -void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out) { +void InitializeX86Context(const WOW64_CONTEXT* context, CPUContextX86* out) { CommonInitializeX86Context(context, out); } -void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out) { +void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out) { memset(out, 0, sizeof(*out)); LOG_IF(ERROR, !HasContextPart(context, CONTEXT_AMD64)) << "non-x64 context"; if (HasContextPart(context, CONTEXT_CONTROL)) { - out->cs = context.SegCs; - out->rflags = context.EFlags; - out->rip = context.Rip; - out->rsp = context.Rsp; + out->cs = context->SegCs; + out->rflags = context->EFlags; + out->rip = context->Rip; + out->rsp = context->Rsp; // SegSs ignored. } if (HasContextPart(context, CONTEXT_INTEGER)) { - out->rax = context.Rax; - out->rbx = context.Rbx; - out->rcx = context.Rcx; - out->rdx = context.Rdx; - out->rdi = context.Rdi; - out->rsi = context.Rsi; - out->rbp = context.Rbp; - out->r8 = context.R8; - out->r9 = context.R9; - out->r10 = context.R10; - out->r11 = context.R11; - out->r12 = context.R12; - out->r13 = context.R13; - out->r14 = context.R14; - out->r15 = context.R15; + out->rax = context->Rax; + out->rbx = context->Rbx; + out->rcx = context->Rcx; + out->rdx = context->Rdx; + out->rdi = context->Rdi; + out->rsi = context->Rsi; + out->rbp = context->Rbp; + out->r8 = context->R8; + out->r9 = context->R9; + out->r10 = context->R10; + out->r11 = context->R11; + out->r12 = context->R12; + out->r13 = context->R13; + out->r14 = context->R14; + out->r15 = context->R15; } if (HasContextPart(context, CONTEXT_SEGMENTS)) { - out->fs = context.SegFs; - out->gs = context.SegGs; + out->fs = context->SegFs; + out->gs = context->SegGs; // SegDs ignored. // SegEs ignored. } if (HasContextPart(context, CONTEXT_DEBUG_REGISTERS)) { - out->dr0 = context.Dr0; - out->dr1 = context.Dr1; - out->dr2 = context.Dr2; - out->dr3 = context.Dr3; + out->dr0 = context->Dr0; + out->dr1 = context->Dr1; + out->dr2 = context->Dr2; + out->dr3 = context->Dr3; // DR4 and DR5 are obsolete synonyms for DR6 and DR7, see // https://en.wikipedia.org/wiki/X86_debug_register. - out->dr4 = context.Dr6; - out->dr5 = context.Dr7; + out->dr4 = context->Dr6; + out->dr5 = context->Dr7; - out->dr6 = context.Dr6; - out->dr7 = context.Dr7; + out->dr6 = context->Dr6; + out->dr7 = context->Dr7; } if (HasContextPart(context, CONTEXT_FLOATING_POINT)) { - static_assert(sizeof(out->fxsave) == sizeof(context.FltSave), + static_assert(sizeof(out->fxsave) == sizeof(context->FltSave), "types must be equivalent"); - memcpy(&out->fxsave, &context.FltSave, sizeof(out->fxsave)); + memcpy(&out->fxsave, &context->FltSave, sizeof(out->fxsave)); } } #elif defined(ARCH_CPU_ARM64) -void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out) { +void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out) { memset(out, 0, sizeof(*out)); LOG_IF(ERROR, !HasContextPart(context, CONTEXT_ARM64)) << "non-arm64 context"; if (HasContextPart(context, CONTEXT_CONTROL)) { - out->spsr = context.Cpsr; - out->pc = context.Pc; - out->regs[30] = context.Lr; - out->sp = context.Sp; - out->regs[29] = context.Fp; + out->spsr = context->Cpsr; + out->pc = context->Pc; + out->regs[30] = context->Lr; + out->sp = context->Sp; + out->regs[29] = context->Fp; } if (HasContextPart(context, CONTEXT_INTEGER)) { - memcpy(&out->regs[0], &context.X0, 18 * sizeof(context.X0)); + memcpy(&out->regs[0], &context->X0, 18 * sizeof(context->X0)); // Don't copy x18 which is reserved as platform register. - memcpy(&out->regs[19], &context.X19, 10 * sizeof(context.X0)); + memcpy(&out->regs[19], &context->X19, 10 * sizeof(context->X0)); } if (HasContextPart(context, CONTEXT_FLOATING_POINT)) { - static_assert(sizeof(out->fpsimd) == sizeof(context.V), + static_assert(sizeof(out->fpsimd) == sizeof(context->V), "types must be equivalent"); - memcpy(&out->fpsimd, &context.V, sizeof(out->fpsimd)); + memcpy(&out->fpsimd, &context->V, sizeof(out->fpsimd)); } } diff --git a/snapshot/win/cpu_context_win.h b/snapshot/win/cpu_context_win.h index 9718f49cb0..69700cfe78 100644 --- a/snapshot/win/cpu_context_win.h +++ b/snapshot/win/cpu_context_win.h @@ -29,7 +29,7 @@ struct CPUContextARM64; //! \brief Initializes a CPUContextX86 structure from a native context structure //! on Windows. -void InitializeX86Context(const CONTEXT& context, CPUContextX86* out); +void InitializeX86Context(const CONTEXT* context, CPUContextX86* out); #endif // ARCH_CPU_X86 @@ -37,11 +37,12 @@ void InitializeX86Context(const CONTEXT& context, CPUContextX86* out); //! \brief Initializes a CPUContextX86 structure from a native context structure //! on Windows. -void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out); +void InitializeX86Context(const WOW64_CONTEXT* context, CPUContextX86* out); //! \brief Initializes a CPUContextX86_64 structure from a native context //! structure on Windows. -void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out); +//! Only reads a max of sizeof(CONTEXT) so will not initialize extended values. +void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out); #endif // ARCH_CPU_X86_64 @@ -49,7 +50,7 @@ void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out); //! \brief Initializes a CPUContextARM64 structure from a native context //! structure on Windows. -void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out); +void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out); #endif // ARCH_CPU_ARM64 diff --git a/snapshot/win/cpu_context_win_test.cc b/snapshot/win/cpu_context_win_test.cc index ab8b8b313a..c6639e4b54 100644 --- a/snapshot/win/cpu_context_win_test.cc +++ b/snapshot/win/cpu_context_win_test.cc @@ -41,7 +41,7 @@ void TestInitializeX86Context() { // directly from the supplied thread, float, and debug state parameters. { CPUContextX86 cpu_context_x86 = {}; - InitializeX86Context(context, &cpu_context_x86); + InitializeX86Context(&context, &cpu_context_x86); EXPECT_EQ(cpu_context_x86.eax, 1u); EXPECT_EQ(cpu_context_x86.fxsave.ftw, 2u); EXPECT_EQ(cpu_context_x86.dr0, 3u); @@ -73,7 +73,7 @@ void TestInitializeX86Context_FsaveWithoutFxsave() { { CPUContextX86 cpu_context_x86 = {}; - InitializeX86Context(context, &cpu_context_x86); + InitializeX86Context(&context, &cpu_context_x86); EXPECT_EQ(cpu_context_x86.eax, 1u); @@ -117,7 +117,7 @@ TEST(CPUContextWin, InitializeX64Context) { // set directly from the supplied thread, float, and debug state parameters. { CPUContextX86_64 cpu_context_x86_64 = {}; - InitializeX64Context(context, &cpu_context_x86_64); + InitializeX64Context(&context, &cpu_context_x86_64); EXPECT_EQ(cpu_context_x86_64.rax, 10u); EXPECT_EQ(cpu_context_x86_64.fxsave.ftw, 11u); EXPECT_EQ(cpu_context_x86_64.dr0, 12u); diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index 29cf165d19..4c9dcfb31c 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -36,7 +36,7 @@ using Context32 = CONTEXT; using Context32 = WOW64_CONTEXT; #endif -void NativeContextToCPUContext32(const Context32& context_record, +void NativeContextToCPUContext32(const Context32* context_record, CPUContext* context, CPUContextUnion* context_union) { context->architecture = kCPUArchitectureX86; @@ -46,7 +46,7 @@ void NativeContextToCPUContext32(const Context32& context_record, #endif // ARCH_CPU_X86_FAMILY #if defined(ARCH_CPU_64_BITS) -void NativeContextToCPUContext64(const CONTEXT& context_record, +void NativeContextToCPUContext64(const CONTEXT* context_record, CPUContext* context, CPUContextUnion* context_union) { #if defined(ARCH_CPU_X86_64) @@ -190,7 +190,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( ProcessReaderWin* process_reader, WinVMAddress exception_pointers_address, DWORD exception_thread_id, - void (*native_to_cpu_context)(const ContextType& context_record, + void (*native_to_cpu_context)(const ContextType* context_record, CPUContext* context, CPUContextUnion* context_union)) { ExceptionPointersType exception_pointers; @@ -232,10 +232,9 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( for (const auto& thread : process_reader->Threads()) { if (thread.id == blame_thread_id) { thread_id_ = blame_thread_id; - native_to_cpu_context( - *reinterpret_cast(&thread.context), - &context_, - &context_union_); + native_to_cpu_context(thread.context.context(), + &context_, + &context_union_); exception_address_ = context_.InstructionPointer(); break; } @@ -266,7 +265,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( return false; } - native_to_cpu_context(context_record, &context_, &context_union_); + native_to_cpu_context(&context_record, &context_, &context_union_); } return true; diff --git a/snapshot/win/exception_snapshot_win.h b/snapshot/win/exception_snapshot_win.h index b8fa73530a..7321d6a93f 100644 --- a/snapshot/win/exception_snapshot_win.h +++ b/snapshot/win/exception_snapshot_win.h @@ -93,7 +93,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot { ProcessReaderWin* process_reader, WinVMAddress exception_pointers_address, DWORD exception_thread_id, - void (*native_to_cpu_context)(const ContextType& context_record, + void (*native_to_cpu_context)(const ContextType* context_record, CPUContext* context, CPUContextUnion* context_union)); diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index e3784caefc..20149faedc 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -143,7 +143,7 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, DCHECK(suspension_state == ProcessSuspensionState::kRunning); thread->suspend_count = 0; DCHECK(!is_64_reading_32); - CaptureContext(&thread->context.native); + thread->context.InitializeFromCurrentThread(); } else { DWORD previous_suspend_count = SuspendThread(thread_handle); if (previous_suspend_count == static_cast(-1)) { @@ -162,25 +162,18 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, (suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0); } - memset(&thread->context, 0, sizeof(thread->context)); #if defined(ARCH_CPU_32_BITS) const bool is_native = true; #elif defined(ARCH_CPU_64_BITS) const bool is_native = !is_64_reading_32; if (is_64_reading_32) { - thread->context.wow64.ContextFlags = CONTEXT_ALL; - if (!Wow64GetThreadContext(thread_handle, &thread->context.wow64)) { - PLOG(ERROR) << "Wow64GetThreadContext"; + if (!thread->context.InitializeWow64(thread_handle)) return false; - } } #endif if (is_native) { - thread->context.native.ContextFlags = CONTEXT_ALL; - if (!GetThreadContext(thread_handle, &thread->context.native)) { - PLOG(ERROR) << "GetThreadContext"; + if (!thread->context.InitializeNative(thread_handle)) return false; - } } if (!ResumeThread(thread_handle)) { @@ -194,6 +187,39 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, } // namespace +ProcessReaderWin::ThreadContext::ThreadContext() + : offset_(0), initialized_(false), data_() {} + +void ProcessReaderWin::ThreadContext::InitializeFromCurrentThread() { + data_.resize(sizeof(CONTEXT)); + initialized_ = true; + CaptureContext(context()); +} + +bool ProcessReaderWin::ThreadContext::InitializeNative(HANDLE thread_handle) { + data_.resize(sizeof(CONTEXT)); + initialized_ = true; + context()->ContextFlags = CONTEXT_ALL; + if (!GetThreadContext(thread_handle, context())) { + PLOG(ERROR) << "GetThreadContext"; + return false; + } + return true; +} + +#if defined(ARCH_CPU_64_BITS) +bool ProcessReaderWin::ThreadContext::InitializeWow64(HANDLE thread_handle) { + data_.resize(sizeof(WOW64_CONTEXT)); + initialized_ = true; + context()->ContextFlags = CONTEXT_ALL; + if (!Wow64GetThreadContext(thread_handle, context())) { + PLOG(ERROR) << "Wow64GetThreadContext"; + return false; + } + return true; +} +#endif + ProcessReaderWin::Thread::Thread() : context(), id(0), @@ -203,8 +229,7 @@ ProcessReaderWin::Thread::Thread() stack_region_size(0), suspend_count(0), priority_class(0), - priority(0) { -} + priority(0) {} ProcessReaderWin::ProcessReaderWin() : process_(INVALID_HANDLE_VALUE), diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index 7875de0412..dc41a20737 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -40,17 +40,39 @@ enum class ProcessSuspensionState : bool { //! \brief Accesses information about another process, identified by a `HANDLE`. class ProcessReaderWin { public: + //! \brief Helper to make the context copyable and resizable. + class ThreadContext { + public: + ThreadContext(); + ~ThreadContext() {} + + template + T* context() const { + DCHECK(initialized_); + return reinterpret_cast( + const_cast(data_.data() + offset_)); + } +#if defined(ARCH_CPU_64_BITS) + bool InitializeWow64(HANDLE thread_handle); +#endif + void InitializeFromCurrentThread(); + bool InitializeNative(HANDLE thread_handle); + + private: + // This is usually 0 but Windows might cause it to be positive when + // fetching the extended context. This needs to be adjusted after + // calls to InitializeContext2(). + size_t offset_; + bool initialized_; + std::vector data_; + }; + //! \brief Contains information about a thread that belongs to a process. struct Thread { Thread(); ~Thread() {} - union { - CONTEXT native; -#if defined(ARCH_CPU_64_BITS) - WOW64_CONTEXT wow64; -#endif - } context; + ThreadContext context; uint64_t id; WinVMAddress teb_address; WinVMSize teb_size; diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 709e56b21a..15a6e2b728 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -111,7 +111,8 @@ TEST(ProcessReaderWin, SelfOneThread) { ASSERT_GE(threads.size(), 1u); EXPECT_EQ(threads[0].id, GetCurrentThreadId()); - EXPECT_NE(ProgramCounterFromCONTEXT(&threads[0].context.native), nullptr); + EXPECT_NE(ProgramCounterFromCONTEXT(threads[0].context.context()), + nullptr); EXPECT_EQ(threads[0].suspend_count, 0u); } diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index c3894a78b1..3a47cf6e66 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -67,21 +67,25 @@ bool ThreadSnapshotWin::Initialize( #if defined(ARCH_CPU_X86) context_.architecture = kCPUArchitectureX86; context_.x86 = &context_union_.x86; - InitializeX86Context(process_reader_thread.context.native, context_.x86); + InitializeX86Context(process_reader_thread.context.context(), + context_.x86); #elif defined(ARCH_CPU_X86_64) if (process_reader->Is64Bit()) { context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_union_.x86_64; - InitializeX64Context(process_reader_thread.context.native, context_.x86_64); + InitializeX64Context(process_reader_thread.context.context(), + context_.x86_64); } else { context_.architecture = kCPUArchitectureX86; context_.x86 = &context_union_.x86; - InitializeX86Context(process_reader_thread.context.wow64, context_.x86); + InitializeX86Context(process_reader_thread.context.context(), + context_.x86); } #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_union_.arm64; - InitializeARM64Context(process_reader_thread.context.native, context_.arm64); + InitializeARM64Context(process_reader_thread.context.context(), + context_.arm64); #else #error Unsupported Windows Arch #endif // ARCH_CPU_X86 From 25222891c74f373b826e2d5d59cec910de4a07a1 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Sat, 14 May 2022 22:40:17 -0700 Subject: [PATCH 164/478] Add fields for shadow stack registers to x64 snapshot This will be used in a later CL to shuttle shadow stack information from capture to minidumps. For now these fields are zeroed and have no effect on any platform. The x64 snapshot context we use no longer directly maps to the early CONTEXT structure used by Windows (the prelude still matches). This may cause confusion if people use the size of a snapshot context when they meant to use sizeof(CONTEXT). Bug: 1250098 Change-Id: Idac7d888b9e606ceb250c4027e0e7f29f4c0a55f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536963 Reviewed-by: Joshua Peraza Commit-Queue: Alex Gough --- snapshot/cpu_context.cc | 29 +++++++++++++++++++++++++++++ snapshot/cpu_context.h | 20 ++++++++++++++++++++ snapshot/test/test_cpu_context.cc | 3 +++ 3 files changed, 52 insertions(+) diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc index 2e29f70398..9b7b3f14f1 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -192,6 +192,35 @@ uint64_t CPUContext::StackPointer() const { } } +uint64_t CPUContext::ShadowStackPointer() const { + switch (architecture) { + case kCPUArchitectureX86: + case kCPUArchitectureARM: + case kCPUArchitectureARM64: + NOTREACHED(); + return 0; + case kCPUArchitectureX86_64: + return x86_64->xstate.cet_u.ssp; + default: + NOTREACHED(); + return ~0ull; + } +} + +bool CPUContext::HasShadowStack() const { + switch (architecture) { + case kCPUArchitectureX86: + case kCPUArchitectureARM: + case kCPUArchitectureARM64: + return false; + case kCPUArchitectureX86_64: + return x86_64->xstate.cet_u.cetmsr != 0; + default: + NOTREACHED(); + return false; + } +} + bool CPUContext::Is64Bit() const { switch (architecture) { case kCPUArchitectureX86_64: diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h index fb23c4679f..4e21b56c59 100644 --- a/snapshot/cpu_context.h +++ b/snapshot/cpu_context.h @@ -257,6 +257,16 @@ struct CPUContextX86_64 { uint64_t dr5; // obsolete, normally an alias for dr7 uint64_t dr6; uint64_t dr7; + + struct { + // If 0 then none of the xsave areas are valid. + uint64_t enabled_features; + // CET_U registers if XSTATE_CET_U bit is set in enabled_features. + struct { + uint64_t cetmsr; + uint64_t ssp; + } cet_u; + } xstate; }; //! \brief A context structure carrying ARM CPU state. @@ -369,9 +379,19 @@ struct CPUContext { //! context structure. uint64_t StackPointer() const; + //! \brief Returns the shadow stack pointer value from the context structure. + //! + //! This is a CPU architecture-independent method that is capable of + //! recovering the shadow stack pointer from any supported CPU architecture’s + //! context structure. + uint64_t ShadowStackPointer() const; + //! \brief Returns `true` if this context is for a 64-bit architecture. bool Is64Bit() const; + //! \brief Returns `true` if this context has an active shadow stack pointer. + bool HasShadowStack() const; + //! \brief The CPU architecture of a context structure. This field controls //! the expression of the union. CPUArchitecture architecture; diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 75d9c5a1fa..3b51973e26 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -161,6 +161,9 @@ void InitializeCPUContextX86_64(CPUContext* context, uint32_t seed) { context->x86_64->dr5 = value++; context->x86_64->dr6 = value++; context->x86_64->dr7 = value++; + + // Make sure this is sensible. When supplied the size/state come from the OS. + memset(&context->x86_64->xstate, 0, sizeof(context->x86_64->xstate)); } void InitializeCPUContextARM(CPUContext* context, uint32_t seed) { From 9e0051aba6ac7ba55557a2ffa74ecb90543e25c8 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Sat, 14 May 2022 22:40:24 -0700 Subject: [PATCH 165/478] Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza Commit-Queue: Alex Gough --- compat/non_win/dbghelp.h | 5 + compat/non_win/winnt.h | 11 ++ minidump/minidump_context.h | 47 ++++++++- minidump/minidump_context_writer.cc | 109 +++++++++++++++++++- minidump/minidump_context_writer.h | 39 +++++++ minidump/minidump_context_writer_test.cc | 24 +++++ minidump/minidump_file_writer.cc | 3 + minidump/minidump_misc_info_writer.cc | 49 +++++++++ minidump/minidump_misc_info_writer.h | 3 + minidump/test/minidump_context_test_util.cc | 10 +- 10 files changed, 295 insertions(+), 5 deletions(-) diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 0d9852bb69..1f8013531b 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -1100,6 +1100,11 @@ enum MINIDUMP_TYPE { //! MINIDUMP_MEMORY_DESCRIPTOR containing the 256 bytes centered around //! the exception address or the instruction pointer. MiniDumpNormal = 0x00000000, + + //! \brief A minidump with extended contexts. + //! + //! Contains Normal plus a MISC_INFO_5 structure describing the contexts. + MiniDumpWithAvxXStateContext = 0x00200000, }; #endif // CRASHPAD_COMPAT_NON_WIN_DBGHELP_H_ diff --git a/compat/non_win/winnt.h b/compat/non_win/winnt.h index f2ed6ace07..376e27cd7a 100644 --- a/compat/non_win/winnt.h +++ b/compat/non_win/winnt.h @@ -155,6 +155,17 @@ //! Architecture (253665-060), 13.4.2 “XSAVE Header”. #define MAXIMUM_XSTATE_FEATURES (64) +//! \anchor XSTATE_x +//! \name XSTATE_* +//! +//! \brief Offsets and constants for extended state. +//! \{ +#define XSTATE_COMPACTION_ENABLE (63) +#define XSTATE_COMPACTION_ENABLE_MASK (1ull << XSTATE_COMPACTION_ENABLE) +#define XSTATE_CET_U (11) +#define XSTATE_MASK_CET_U (1ull << XSTATE_CET_U) +//! \} + //! \brief The location of a single state component within an XSAVE area. struct XSTATE_FEATURE { //! \brief The location of a state component within a CPU-specific context diff --git a/minidump/minidump_context.h b/minidump/minidump_context.h index 3a3e603cb0..c10743d848 100644 --- a/minidump/minidump_context.h +++ b/minidump/minidump_context.h @@ -225,7 +225,7 @@ enum MinidumpContextAMD64Flags : uint32_t { //! \brief Indicates the validity of `xsave` data (`CONTEXT_XSTATE`). //! //! The context contains `xsave` data. This is used with an extended context - //! structure not currently defined here. + //! structure which is partly implemented for CET state only. kMinidumpContextAMD64Xstate = kMinidumpContextAMD64 | 0x00000040, //! \brief Indicates the validity of control, integer, and floating-point @@ -386,6 +386,51 @@ struct MinidumpContextARM { uint32_t extra[8]; }; +//! \brief CONTEXT_CHUNK +struct MinidumpContextChunk { + int32_t offset; + uint32_t size; +}; + +//! \brief CONTEXT_EX +struct MinidumpContextExHeader { + MinidumpContextChunk all; + MinidumpContextChunk legacy; + MinidumpContextChunk xstate; +}; + +//! \brief XSAVE_AREA_HEADER +struct MinidumpXSaveAreaHeader { + uint64_t mask; + uint64_t compaction_mask; + uint64_t xsave_header_reserved[6]; +}; + +//! \brief Offset of first xsave feature in the full extended context. +//! +//! This is used to calculate the final size of the extended context, and +//! can be validated by calling InitializeContext2 with one XSTATE feature, +//! and LocateXStateFeature to determine the first offset. +//! Also see "MANAGING STATE USING THE XSAVE FEATURE SET", Ch. 13, Intel SDM. +constexpr uint32_t kMinidumpAMD64XSaveOffset = 0x550; + +//! \brief Offset of first xsave feature within the extended context area. +//! +//! 0x240 is the size of the legacy area (512) + the xsave header(64 bytes) +//! Intel SDM 13.4.1. This is not where the item is in the extended compacted +//! context, but is the offset recorded in the minidump. It needs to be correct +//! there. See https://windows-internals.com/cet-on-windows/ for some discussion +//! "CONTEXT_XSTATE: Extended processor state chunk. The state is stored in the +//! same format the XSAVE operation stores it with exception of the first 512 +//! bytes, i.e. starting from XSAVE_AREA_HEADER." This may vary by cpuid. +constexpr uint32_t kXSaveAreaFirstOffset = 0x240; + +//! \brief XSAVE_CET_U_FORMAT +struct MinidumpAMD64XSaveFormatCetU { + uint64_t cetmsr; + uint64_t ssp; +}; + //! \brief 64-bit ARM-specifc flags for MinidumpContextARM64::context_flags. enum MinidumpContextARM64Flags : uint32_t { //! \brief Identifies the context structure as 64-bit ARM. diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index 2f2d90ba47..6ae25b8fe1 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -118,6 +118,11 @@ size_t MinidumpContextWriter::SizeOfObject() { return ContextSize(); } +size_t MinidumpContextWriter::FreezeAndGetSizeOfObject() { + Freeze(); + return SizeOfObject(); +} + MinidumpContextX86Writer::MinidumpContextX86Writer() : MinidumpContextWriter(), context_() { context_.context_flags = kMinidumpContextX86; @@ -213,7 +218,14 @@ void MinidumpContextAMD64Writer::InitializeFromSnapshot( DCHECK_EQ(state(), kStateMutable); DCHECK_EQ(context_.context_flags, kMinidumpContextAMD64); - context_.context_flags = kMinidumpContextAMD64All; + if (context_snapshot->xstate.enabled_features != 0) { + // Extended context. + context_.context_flags = + kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate; + } else { + // Fixed size context - no xsave components. + context_.context_flags = kMinidumpContextAMD64All; + } context_.mx_csr = context_snapshot->fxsave.mxcsr; context_.cs = context_snapshot->cs; @@ -247,6 +259,15 @@ void MinidumpContextAMD64Writer::InitializeFromSnapshot( // This is effectively a memcpy() of a big structure. context_.fxsave = context_snapshot->fxsave; + + // If XSave features are being recorded store in xsave_entries in xcomp_bv + // order. We will not see features we do not support as we provide flags + // to the OS when first obtaining a snapshot. + if (context_snapshot->xstate.enabled_features & XSTATE_MASK_CET_U) { + auto cet_u = std::make_unique(); + cet_u->InitializeFromSnapshot(context_snapshot); + xsave_entries_.push_back(std::move(cet_u)); + } } size_t MinidumpContextAMD64Writer::Alignment() { @@ -258,14 +279,96 @@ size_t MinidumpContextAMD64Writer::Alignment() { bool MinidumpContextAMD64Writer::WriteObject(FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); + // Note: all sizes here come from our constants, not from untrustworthy data. + std::vector data(ContextSize()); + unsigned char* const buf = data.data(); + + // CONTEXT always comes first. + DCHECK_LE(sizeof(context_), data.size()); + memcpy(buf, &context_, sizeof(context_)); + + if (xsave_entries_.size() > 0) { + MinidumpContextExHeader context_ex = {{0}, {0}, {0}}; + MinidumpXSaveAreaHeader xsave_header = {0}; + + // CONTEXT_EX goes directly after the CONTEXT. |offset| is relative to + // &CONTEXT_EX. + context_ex.all.offset = -static_cast(sizeof(context_)); + context_ex.all.size = static_cast(ContextSize()); + context_ex.legacy.offset = context_ex.all.offset; + context_ex.legacy.size = sizeof(context_); + // Then... there is a gap. + // + // In the compacted format the XSave area header goes just before + // the first xsave entry. It has a total size given by the header + // + (padded) sizes of all the entries. + context_ex.xstate.offset = static_cast( + kMinidumpAMD64XSaveOffset - sizeof(MinidumpXSaveAreaHeader) - + sizeof(context_)); + context_ex.xstate.size = + static_cast(sizeof(MinidumpXSaveAreaHeader) + ContextSize() - + kMinidumpAMD64XSaveOffset); + + // Store CONTEXT_EX now it is complete. + DCHECK_LE(sizeof(context_) + sizeof(context_ex), data.size()); + memcpy(&buf[sizeof(context_)], &context_ex, sizeof(context_ex)); + + // Calculate flags for xsave header & write entries (they will be + // *after* the xsave header). + size_t cursor = kMinidumpAMD64XSaveOffset; + for (auto const& entry : xsave_entries_) { + xsave_header.mask |= 1ull << entry->XCompBVBit(); + DCHECK_LE(cursor + entry->Size(), data.size()); + entry->Copy(&buf[cursor]); + cursor += entry->Size(); + } - return file_writer->Write(&context_, sizeof(context_)); + xsave_header.compaction_mask = + xsave_header.mask | XSTATE_COMPACTION_ENABLE_MASK; + + // Store xsave header at its calculated offset. It is before the entries + // above, but we need to add the |mask| bits before writing it. + DCHECK_LE( + context_ex.xstate.offset + sizeof(context_) + sizeof(xsave_header), + data.size()); + memcpy(&buf[context_ex.xstate.offset + sizeof(context_)], + &xsave_header, + sizeof(xsave_header)); + } + + if (!file_writer->Write(data.data(), data.size())) + return false; + + return true; } size_t MinidumpContextAMD64Writer::ContextSize() const { DCHECK_GE(state(), kStateFrozen); + if (xsave_entries_.size() == 0) { + return sizeof(context_); + } else { + DCHECK_EQ(context_.context_flags, + kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate); + DCHECK(xsave_entries_.size() != 0); + size_t size = kMinidumpAMD64XSaveOffset; + for (auto& entry : xsave_entries_) { + size += entry->Size(); + } + return size; + } +} - return sizeof(context_); +bool MinidumpXSaveAMD64CetU::InitializeFromSnapshot( + const CPUContextX86_64* context_snapshot) { + DCHECK_EQ(context_snapshot->xstate.cet_u.cetmsr, 1ull); + cet_u_.cetmsr = context_snapshot->xstate.cet_u.cetmsr; + cet_u_.ssp = context_snapshot->xstate.cet_u.ssp; + return true; +} + +bool MinidumpXSaveAMD64CetU::Copy(void* dst) const { + memcpy(dst, &cet_u_, sizeof(cet_u_)); + return true; } MinidumpContextARMWriter::MinidumpContextARMWriter() diff --git a/minidump/minidump_context_writer.h b/minidump/minidump_context_writer.h index 80b312b23c..9acc7fa012 100644 --- a/minidump/minidump_context_writer.h +++ b/minidump/minidump_context_writer.h @@ -27,6 +27,7 @@ namespace crashpad { struct CPUContext; struct CPUContextX86; struct CPUContextX86_64; +class MinidumpMiscInfoWriter; //! \brief The base class for writers of CPU context structures in minidump //! files. @@ -49,6 +50,12 @@ class MinidumpContextWriter : public internal::MinidumpWritable { static std::unique_ptr CreateFromSnapshot( const CPUContext* context_snapshot); + //! \brief Returns the size of the context structure that this object will + //! write. + //! + //! \note This method will force this to #kStateFrozen, if it is not already. + size_t FreezeAndGetSizeOfObject(); + protected: MinidumpContextWriter() : MinidumpWritable() {} @@ -105,6 +112,36 @@ class MinidumpContextX86Writer final : public MinidumpContextWriter { MinidumpContextX86 context_; }; +//! \brief Wraps an xsave feature that knows where and how big it is. +class MinidumpXSaveFeatureAMD64 { + public: + virtual ~MinidumpXSaveFeatureAMD64() = default; + // Number of bytes that will be written. May need to vary by CPUID (see + // Intel 13.5). + virtual size_t Size() const = 0; + // Intel 13.4.2 XCOMP_BV. + virtual uint8_t XCompBVBit() const = 0; + // Write data to dst. Does not write padding. + virtual bool Copy(void* dst) const = 0; +}; + +//! \brief XSAVE_CET_U_FORMAT +class MinidumpXSaveAMD64CetU final : public MinidumpXSaveFeatureAMD64 { + public: + MinidumpXSaveAMD64CetU() {} + ~MinidumpXSaveAMD64CetU() {} + MinidumpXSaveAMD64CetU(const MinidumpXSaveAMD64CetU&) = delete; + MinidumpXSaveAMD64CetU& operator=(const MinidumpXSaveAMD64CetU&) = delete; + + size_t Size() const override { return sizeof(cet_u_); } + uint8_t XCompBVBit() const override { return XSTATE_CET_U; } + bool Copy(void* dst) const override; + bool InitializeFromSnapshot(const CPUContextX86_64* context_snapshot); + + private: + MinidumpAMD64XSaveFormatCetU cet_u_; +}; + //! \brief The writer for a MinidumpContextAMD64 structure in a minidump file. class MinidumpContextAMD64Writer final : public MinidumpContextWriter { public: @@ -157,6 +194,8 @@ class MinidumpContextAMD64Writer final : public MinidumpContextWriter { private: MinidumpContextAMD64 context_; + // These should be in order of XCompBVBit(). + std::vector> xsave_entries_; }; //! \brief The writer for a MinidumpContextARM structure in a minidump file. diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc index 3216a906ba..b4bfdbdb64 100644 --- a/minidump/minidump_context_writer_test.cc +++ b/minidump/minidump_context_writer_test.cc @@ -153,6 +153,30 @@ TEST(MinidumpContextWriter, AMD64_FromSnapshot) { context, ExpectMinidumpContextAMD64, kSeed); } +TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) { + constexpr uint32_t kSeed = 77; + CPUContextX86_64 context_x86_64; + CPUContext context; + context.x86_64 = &context_x86_64; + InitializeCPUContextX86_64(&context, kSeed); + context_x86_64.xstate.enabled_features |= XSTATE_MASK_CET_U; + context_x86_64.xstate.cet_u.cetmsr = 1; + context_x86_64.xstate.cet_u.ssp = kSeed * kSeed; + // We cannot use FromSnapshotTest as we write more than the fixed context. + std::unique_ptr context_writer = + MinidumpContextWriter::CreateFromSnapshot(&context); + ASSERT_TRUE(context_writer); + + StringFile string_file; + ASSERT_TRUE(context_writer->WriteEverything(&string_file)); + + const MinidumpContextAMD64* observed = + MinidumpWritableAtRVA(string_file.string(), 0); + ASSERT_TRUE(observed); + + ExpectMinidumpContextAMD64(kSeed, observed, true); +} + TEST(MinidumpContextWriter, ARM_Zeros) { EmptyContextTest( ExpectMinidumpContextARM); diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 6727a0dcda..43abca84c0 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -79,6 +79,9 @@ void MinidumpFileWriter::InitializeFromSnapshot( auto misc_info = std::make_unique(); misc_info->InitializeFromSnapshot(process_snapshot); + if (misc_info->HasXStateData()) + header_.Flags = header_.Flags | MiniDumpWithAvxXStateContext; + add_stream_result = AddStream(std::move(misc_info)); DCHECK(add_stream_result); diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index 78847c1197..51c91c4c90 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -23,10 +23,13 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "minidump/minidump_context_writer.h" #include "minidump/minidump_writer_util.h" #include "package.h" +#include "snapshot/cpu_context.h" #include "snapshot/process_snapshot.h" #include "snapshot/system_snapshot.h" +#include "snapshot/thread_snapshot.h" #include "util/file/file_writer.h" #include "util/numeric/in_range_cast.h" #include "util/numeric/safe_assignment.h" @@ -95,6 +98,43 @@ int AvailabilityVersionToMacOSVersionNumber(int availability) { } #endif // BUILDFLAG(IS_MAC) +bool MaybeSetXStateData(const ProcessSnapshot* process_snapshot, + XSTATE_CONFIG_FEATURE_MSC_INFO* xstate) { + // Cannot set xstate data if there are no threads. + auto threads = process_snapshot->Threads(); + if (threads.size() == 0) + return false; + + // All threads should be the same as we request contexts in the same way. + auto context = threads.at(0)->Context(); + + // Only support AMD64. + if (context->architecture != kCPUArchitectureX86_64) + return false; + + // If no extended features, then we will just write the standard context. + if (context->x86_64->xstate.enabled_features == 0) + return false; + + xstate->SizeOfInfo = sizeof(*xstate); + // Needs to match the size of the context we'll write or the dump is invalid, + // so ask the first thread how large it will be. + auto context_writer = MinidumpContextWriter::CreateFromSnapshot(context); + xstate->ContextSize = + static_cast(context_writer->FreezeAndGetSizeOfObject()); + // Note: This isn't the same as xstateenabledfeatures! + xstate->EnabledFeatures = + context->x86_64->xstate.enabled_features | XSTATE_COMPACTION_ENABLE_MASK; + + // Note: if other XSAVE entries are to be supported they will be in order, + // and may have different offsets depending on what is saved. + if (context->x86_64->xstate.enabled_features & XSTATE_MASK_CET_U) { + xstate->Features[XSTATE_CET_U].Offset = kXSaveAreaFirstOffset; + xstate->Features[XSTATE_CET_U].Size = sizeof(MinidumpAMD64XSaveFormatCetU); + } + return true; +} + } // namespace namespace internal { @@ -235,6 +275,11 @@ void MinidumpMiscInfoWriter::InitializeFromSnapshot( SetBuildString(BuildString(system_snapshot), internal::MinidumpMiscInfoDebugBuildString()); + + XSTATE_CONFIG_FEATURE_MSC_INFO xstate{}; + if (MaybeSetXStateData(process_snapshot, &xstate)) { + SetXStateData(xstate); + } } void MinidumpMiscInfoWriter::SetProcessID(uint32_t process_id) { @@ -353,6 +398,10 @@ void MinidumpMiscInfoWriter::SetXStateData( has_xstate_data_ = true; } +bool MinidumpMiscInfoWriter::HasXStateData() const { + return has_xstate_data_; +} + void MinidumpMiscInfoWriter::SetProcessCookie(uint32_t process_cookie) { DCHECK_EQ(state(), kStateMutable); diff --git a/minidump/minidump_misc_info_writer.h b/minidump/minidump_misc_info_writer.h index 9d89fe6480..cdaa0e4937 100644 --- a/minidump/minidump_misc_info_writer.h +++ b/minidump/minidump_misc_info_writer.h @@ -118,6 +118,9 @@ class MinidumpMiscInfoWriter final : public internal::MinidumpStreamWriter { //! \brief Sets MINIDUMP_MISC_INFO_5::XStateData. void SetXStateData(const XSTATE_CONFIG_FEATURE_MSC_INFO& xstate_data); + //! \brief Will this write extended context information? + bool HasXStateData() const; + //! \brief Sets the field referenced by #MINIDUMP_MISC5_PROCESS_COOKIE. void SetProcessCookie(uint32_t process_cookie); diff --git a/minidump/test/minidump_context_test_util.cc b/minidump/test/minidump_context_test_util.cc index 3836640c04..06afacf460 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -383,7 +383,15 @@ void ExpectMinidumpContextAMD64( MinidumpContextAMD64 expected; InitializeMinidumpContextAMD64(&expected, expect_seed); - EXPECT_EQ(observed->context_flags, expected.context_flags); + // Allow context_flags to include xstate bit - this is added if we will write + // an extended context, but is not generated in the fixed context for testing. + if ((observed->context_flags & kMinidumpContextAMD64Xstate) == + kMinidumpContextAMD64Xstate) { + EXPECT_EQ(observed->context_flags, + (expected.context_flags | kMinidumpContextAMD64Xstate)); + } else { + EXPECT_EQ(observed->context_flags, expected.context_flags); + } if (snapshot) { EXPECT_EQ(observed->p1_home, 0u); From 9ef737a26ddeed583226f255c6cec5d22ddefb3b Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Mon, 16 May 2022 15:38:37 -0700 Subject: [PATCH 166/478] Captures shadow stack registers for x64 Windows contexts Windows extended contexts must be allocated by InitializeContext2 and may not be aligned. This means we cannot simply store a struct in our thread snapshot object, but must instead store enough memory and alias our struct onto this backing memory. Note that shadow stack pointers are not yet recorded for the initial exception - this cannot be determined using LocateXStateFeature in the capturing process and will be added in a future CL by plumbing through client messages when a crashed process requests a dump. See crash/32bd2c53a252705c for an example dump with this baked into chrome, that has passed through breakpad without breaking it. Local testing shows this creates valid dumps when built into Chrome, but that the referenced memory limits may need to be increased to allow for ssp referenced memory to be included. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[0]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[1]. [0] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [1] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: I4b13bcb023e9d5fba257044abfd7e251d66a9329 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3300992 Reviewed-by: Joshua Peraza Commit-Queue: Alex Gough --- snapshot/capture_memory.cc | 8 ++++ snapshot/win/cpu_context_win.cc | 30 +++++++++++++ snapshot/win/cpu_context_win.h | 10 +++++ snapshot/win/exception_snapshot_win.cc | 12 ++++++ snapshot/win/process_reader_win.cc | 60 +++++++++++++++++++++++--- snapshot/win/process_reader_win.h | 2 + snapshot/win/thread_snapshot_win.cc | 31 ++++++++++++- 7 files changed, 146 insertions(+), 7 deletions(-) diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index 06d9258133..3ff099fe00 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -15,6 +15,10 @@ #include "snapshot/capture_memory.h" #include +#include + +// dbghelp must be after windows.h. +#include #include #include @@ -86,6 +90,10 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, MaybeCaptureMemoryAround(delegate, context.x86_64->r14); MaybeCaptureMemoryAround(delegate, context.x86_64->r15); MaybeCaptureMemoryAround(delegate, context.x86_64->rip); + // Shadow stack region. + if (context.x86_64->xstate.enabled_features & XSTATE_MASK_CET_U) { + MaybeCaptureMemoryAround(delegate, context.x86_64->xstate.cet_u.ssp); + } } else { MaybeCaptureMemoryAround(delegate, context.x86->eax); MaybeCaptureMemoryAround(delegate, context.x86->ebx); diff --git a/snapshot/win/cpu_context_win.cc b/snapshot/win/cpu_context_win.cc index 0d7783829a..e79c94b307 100644 --- a/snapshot/win/cpu_context_win.cc +++ b/snapshot/win/cpu_context_win.cc @@ -124,6 +124,19 @@ void CommonInitializeX86Context(const T* context, CPUContextX86* out) { } } +#if defined(ARCH_CPU_X86_64) +DWORD64 CallGetEnabledXStateFeatures() { + // GetEnabledXStateFeatures needs Windows 7 SP1. + HINSTANCE kernel32 = GetModuleHandle(L"Kernel32.dll"); + decltype(GetEnabledXStateFeatures)* get_enabled_xstate_features = + reinterpret_cast( + GetProcAddress(kernel32, "GetEnabledXStateFeatures")); + if (!get_enabled_xstate_features) + return 0; + return get_enabled_xstate_features(); +} +#endif // defined(ARCH_CPU_X64) + } // namespace #if defined(ARCH_CPU_X86) @@ -198,6 +211,23 @@ void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out) { } } +void InitializeX64XStateCet(const CONTEXT* context, + XSAVE_CET_U_FORMAT* cet_u, + CPUContextX86_64* out) { + if (HasContextPart(context, CONTEXT_XSTATE)) { + if (cet_u) { + out->xstate.enabled_features |= XSTATE_MASK_CET_U; + out->xstate.cet_u.cetmsr = cet_u->Ia32CetUMsr; + out->xstate.cet_u.ssp = cet_u->Ia32Pl3SspMsr; + } + } +} + +bool IsXStateFeatureEnabled(DWORD64 features) { + static DWORD64 flags = CallGetEnabledXStateFeatures(); + return (flags & features) == features; +} + #elif defined(ARCH_CPU_ARM64) void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out) { diff --git a/snapshot/win/cpu_context_win.h b/snapshot/win/cpu_context_win.h index 69700cfe78..720474d3c7 100644 --- a/snapshot/win/cpu_context_win.h +++ b/snapshot/win/cpu_context_win.h @@ -44,6 +44,16 @@ void InitializeX86Context(const WOW64_CONTEXT* context, CPUContextX86* out); //! Only reads a max of sizeof(CONTEXT) so will not initialize extended values. void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out); +//! \brief Initializes CET fields of a CPUContextX86_64 structure from +//! an xsave location if |context| flags support cet_u values. +void InitializeX64XStateCet(const CONTEXT* context, + XSAVE_CET_U_FORMAT* cet_u, + CPUContextX86_64* out); + +//! \brief Wraps GetXStateEnabledFeatures(), returns true if the specified set +//! of flags are all supported. +bool IsXStateFeatureEnabled(DWORD64 feature); + #endif // ARCH_CPU_X86_64 #if defined(ARCH_CPU_ARM64) || DOXYGEN diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index 4c9dcfb31c..d1df987c6d 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -52,7 +52,19 @@ void NativeContextToCPUContext64(const CONTEXT* context_record, #if defined(ARCH_CPU_X86_64) context->architecture = kCPUArchitectureX86_64; context->x86_64 = &context_union->x86_64; + // Note that the context here is not extended, even if the flags suggest so, + // as we only copied in sizeof(CONTEXT). InitializeX64Context(context_record, context->x86_64); + // TODO(1250098) plumb through ssp via message from crashed process. For now + // we zero this if CET is available in the capturing process as otherwise + // WinDBG will show the relevant thread's ssp for the exception which will + // likely be more confusing than showing a zero value. + if (IsXStateFeatureEnabled(XSTATE_MASK_CET_U)) { + XSAVE_CET_U_FORMAT cet_u_fake; + cet_u_fake.Ia32CetUMsr = 0; + cet_u_fake.Ia32Pl3SspMsr = 0; + InitializeX64XStateCet(context_record, &cet_u_fake, context->x86_64); + } #elif defined(ARCH_CPU_ARM64) context->architecture = kCPUArchitectureARM64; context->arm64 = &context_union->arm64; diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index 20149faedc..a437a148bb 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -19,7 +19,9 @@ #include +#include "base/notreached.h" #include "base/numerics/safe_conversions.h" +#include "snapshot/win/cpu_context_win.h" #include "util/misc/capture_context.h" #include "util/misc/time.h" #include "util/win/nt_internals.h" @@ -163,18 +165,20 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, } #if defined(ARCH_CPU_32_BITS) - const bool is_native = true; + if (!thread->context.InitializeNative(thread_handle)) + return false; #elif defined(ARCH_CPU_64_BITS) - const bool is_native = !is_64_reading_32; if (is_64_reading_32) { if (!thread->context.InitializeWow64(thread_handle)) return false; - } -#endif - if (is_native) { + } else if (IsXStateFeatureEnabled(XSTATE_MASK_CET_U)) { + if (!thread->context.InitializeXState(thread_handle, XSTATE_MASK_CET_U)) + return false; + } else { if (!thread->context.InitializeNative(thread_handle)) return false; } +#endif if (!ResumeThread(thread_handle)) { PLOG(ERROR) << "ResumeThread"; @@ -220,6 +224,52 @@ bool ProcessReaderWin::ThreadContext::InitializeWow64(HANDLE thread_handle) { } #endif +#if defined(ARCH_CPU_64_BITS) +bool ProcessReaderWin::ThreadContext::InitializeXState( + HANDLE thread_handle, + ULONG64 XStateCompactionMask) { + static auto initialize_context_2 = []() { + // InitializeContext2 needs Windows 10 build 20348. + HINSTANCE kernel32 = GetModuleHandle(L"Kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32, "InitializeContext2")); + }(); + if (!initialize_context_2) + return false; + // We want CET_U xstate to get the ssp, only possible when supported. + PCONTEXT ret_context = nullptr; + DWORD context_size = 0; + if (!initialize_context_2(nullptr, + CONTEXT_ALL | CONTEXT_XSTATE, + &ret_context, + &context_size, + XStateCompactionMask) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + PLOG(ERROR) << "InitializeContext2 - getting required size"; + return false; + } + // NB: ret_context may not be data.begin(). + data_.resize(context_size); + if (!initialize_context_2(data_.data(), + CONTEXT_ALL | CONTEXT_XSTATE, + &ret_context, + &context_size, + XStateCompactionMask)) { + PLOG(ERROR) << "InitializeContext2 - initializing"; + return false; + } + offset_ = reinterpret_cast(ret_context) - data_.data(); + initialized_ = true; + + if (!GetThreadContext(thread_handle, ret_context)) { + PLOG(ERROR) << "GetThreadContext"; + return false; + } + + return true; +} +#endif // defined(ARCH_CPU_64_BITS) + ProcessReaderWin::Thread::Thread() : context(), id(0), diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index dc41a20737..72b0c8d68c 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -54,6 +54,8 @@ class ProcessReaderWin { } #if defined(ARCH_CPU_64_BITS) bool InitializeWow64(HANDLE thread_handle); + // Initializes internal structures for extended compacted contexts. + bool InitializeXState(HANDLE thread_handle, ULONG64 XStateCompactionMask); #endif void InitializeFromCurrentThread(); bool InitializeNative(HANDLE thread_handle); diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index 3a47cf6e66..9286b39269 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -26,6 +26,25 @@ namespace crashpad { namespace internal { +namespace { +#if defined(ARCH_CPU_X86_64) +XSAVE_CET_U_FORMAT* LocateXStateCetU(CONTEXT* context) { + // GetEnabledXStateFeatures needs Windows 7 SP1. + static auto locate_xstate_feature = []() { + HINSTANCE kernel32 = GetModuleHandle(L"Kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32, "LocateXStateFeature")); + }(); + if (!locate_xstate_feature) + return nullptr; + + DWORD cet_u_size = 0; + return reinterpret_cast( + locate_xstate_feature(context, XSTATE_CET_U, &cet_u_size)); +} +#endif // defined(ARCH_CPU_X86_64) +} // namespace + ThreadSnapshotWin::ThreadSnapshotWin() : ThreadSnapshot(), context_(), @@ -73,8 +92,16 @@ bool ThreadSnapshotWin::Initialize( if (process_reader->Is64Bit()) { context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_union_.x86_64; - InitializeX64Context(process_reader_thread.context.context(), - context_.x86_64); + CONTEXT* context = process_reader_thread.context.context(); + InitializeX64Context(context, context_.x86_64); + // Capturing process must have CET enabled. If captured process does not, + // then this will not set any state in the context snapshot. + if (IsXStateFeatureEnabled(XSTATE_MASK_CET_U)) { + XSAVE_CET_U_FORMAT* cet_u = LocateXStateCetU(context); + if (cet_u) { + InitializeX64XStateCet(context, cet_u, context_.x86_64); + } + } } else { context_.architecture = kCPUArchitectureX86; context_.x86 = &context_union_.x86; From d8567ffc5359ab180a0959a7ab7c54fd23ad966c Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Mon, 16 May 2022 16:16:07 -0700 Subject: [PATCH 167/478] Capture shadow stack region if available Where shadow stacks are available, capture the entire shadow stack page unconditionally. Bug: 1250098 Change-Id: I5e2273c19b5f2d571195ff1252396df7dd70566a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3493684 Commit-Queue: Alex Gough Reviewed-by: Joshua Peraza --- snapshot/capture_memory.cc | 5 +---- snapshot/win/thread_snapshot_win.cc | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index 3ff099fe00..cb8231bdb9 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -90,10 +90,7 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, MaybeCaptureMemoryAround(delegate, context.x86_64->r14); MaybeCaptureMemoryAround(delegate, context.x86_64->r15); MaybeCaptureMemoryAround(delegate, context.x86_64->rip); - // Shadow stack region. - if (context.x86_64->xstate.enabled_features & XSTATE_MASK_CET_U) { - MaybeCaptureMemoryAround(delegate, context.x86_64->xstate.cet_u.ssp); - } + // Note: Shadow stack region is directly captured. } else { MaybeCaptureMemoryAround(delegate, context.x86->eax); MaybeCaptureMemoryAround(delegate, context.x86->ebx); diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index 9286b39269..2c5569f8f1 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -18,6 +18,8 @@ #include #include "base/check_op.h" +#include "base/memory/page_size.h" +#include "base/numerics/safe_conversions.h" #include "snapshot/capture_memory.h" #include "snapshot/win/capture_memory_delegate_win.h" #include "snapshot/win/cpu_context_win.h" @@ -28,6 +30,7 @@ namespace internal { namespace { #if defined(ARCH_CPU_X86_64) + XSAVE_CET_U_FORMAT* LocateXStateCetU(CONTEXT* context) { // GetEnabledXStateFeatures needs Windows 7 SP1. static auto locate_xstate_feature = []() { @@ -98,7 +101,7 @@ bool ThreadSnapshotWin::Initialize( // then this will not set any state in the context snapshot. if (IsXStateFeatureEnabled(XSTATE_MASK_CET_U)) { XSAVE_CET_U_FORMAT* cet_u = LocateXStateCetU(context); - if (cet_u) { + if (cet_u && cet_u->Ia32CetUMsr && cet_u->Ia32Pl3SspMsr) { InitializeX64XStateCet(context, cet_u, context_.x86_64); } } @@ -117,6 +120,22 @@ bool ThreadSnapshotWin::Initialize( #error Unsupported Windows Arch #endif // ARCH_CPU_X86 +#if defined(ARCH_CPU_X86_64) + // Unconditionally store page around ssp if it is present. + if (process_reader->Is64Bit() && context_.x86_64->xstate.cet_u.ssp) { + WinVMAddress page_size = + base::checked_cast(base::GetPageSize()); + WinVMAddress page_mask = ~(page_size - 1); + WinVMAddress ssp_base = context_.x86_64->xstate.cet_u.ssp & page_mask; + if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable( + CheckedRange(ssp_base, page_size))) { + auto region = std::make_unique(); + region->Initialize(process_reader->Memory(), ssp_base, page_size); + pointed_to_memory_.push_back(std::move(region)); + } + } +#endif // ARCH_CPU_X86_64 + CaptureMemoryDelegateWin capture_memory_delegate( process_reader, thread_, From 1fa6eb27f6999da18d4fa3584a3cc88949970f56 Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 17 May 2022 23:31:08 -0700 Subject: [PATCH 168/478] Fix compile for arm64 Some xstate flags are not available in arm64 as it does not have xstate so we should omit the InitializeXState method on the `target_cpu = arm64` configuration. Bug: 1250098 Change-Id: I5c92d6efbe90587bdebef87d4a6ce4e9b25afa4d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3653575 Commit-Queue: Alex Gough Reviewed-by: Joshua Peraza --- snapshot/win/process_reader_win.cc | 12 ++++++++---- snapshot/win/process_reader_win.h | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index a437a148bb..23073803b9 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -167,18 +167,22 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, #if defined(ARCH_CPU_32_BITS) if (!thread->context.InitializeNative(thread_handle)) return false; -#elif defined(ARCH_CPU_64_BITS) +#endif // ARCH_CPU_32_BITS + +#if defined(ARCH_CPU_64_BITS) if (is_64_reading_32) { if (!thread->context.InitializeWow64(thread_handle)) return false; +#if defined(ARCH_CPU_X86_64) } else if (IsXStateFeatureEnabled(XSTATE_MASK_CET_U)) { if (!thread->context.InitializeXState(thread_handle, XSTATE_MASK_CET_U)) return false; +#endif // ARCH_CPU_X86_64 } else { if (!thread->context.InitializeNative(thread_handle)) return false; } -#endif +#endif // ARCH_CPU_64_BITS if (!ResumeThread(thread_handle)) { PLOG(ERROR) << "ResumeThread"; @@ -224,7 +228,7 @@ bool ProcessReaderWin::ThreadContext::InitializeWow64(HANDLE thread_handle) { } #endif -#if defined(ARCH_CPU_64_BITS) +#if defined(ARCH_CPU_X86_64) bool ProcessReaderWin::ThreadContext::InitializeXState( HANDLE thread_handle, ULONG64 XStateCompactionMask) { @@ -268,7 +272,7 @@ bool ProcessReaderWin::ThreadContext::InitializeXState( return true; } -#endif // defined(ARCH_CPU_64_BITS) +#endif // defined(ARCH_CPU_X86_64) ProcessReaderWin::Thread::Thread() : context(), diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index 72b0c8d68c..5987c005c4 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -54,9 +54,11 @@ class ProcessReaderWin { } #if defined(ARCH_CPU_64_BITS) bool InitializeWow64(HANDLE thread_handle); +#endif // ARCH_CPU_64_BITS +#if defined(ARCH_CPU_X86_64) // Initializes internal structures for extended compacted contexts. bool InitializeXState(HANDLE thread_handle, ULONG64 XStateCompactionMask); -#endif +#endif // ARCH_CPU_X86_64 void InitializeFromCurrentThread(); bool InitializeNative(HANDLE thread_handle); From 2071abaeb4deac03c5032581f758c0f20862adf2 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Tue, 17 May 2022 15:18:21 -0600 Subject: [PATCH 169/478] [ios] Fix FD leak in IOSIntermediateDumpWriter IOSIntermediateDumpWriter::Close() is intended to close the FD opened by the in-process handler. Currently, InProcessHandler::ScopedLockedWriter::~ScopedLockedWriter() does invoke IOSIntermediateDumpWriter::Close(). However, InProcessHandler::Initialize() invokes the utility CreateWriterWithPath() which directly creates an IOSIntermediateDumpWriter. It neither uses ScopedLockedWriter nor invokes Close(). This fixes the issue by: 1) Making IOSIntermediateDumpWriter::~IOSIntermediateDumpWriter() DCHECK() that it's closed 2) Calling IOSIntermediateDumpWriter::Close() from InProcessHandler::~InProcessHandler() and from test files Change-Id: Ibfede0a3d2aeac948c7ff3d56445e13d1a4028b5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3648710 Commit-Queue: Justin Cohen Reviewed-by: Justin Cohen --- client/ios_handler/in_process_handler.cc | 3 +++ .../in_process_intermediate_dump_handler_test.cc | 1 + .../process_snapshot_ios_intermediate_dump_test.cc | 1 + util/ios/ios_intermediate_dump_reader_test.cc | 1 + util/ios/ios_intermediate_dump_writer.cc | 12 +++++++++++- util/ios/ios_intermediate_dump_writer.h | 6 +++++- util/ios/ios_intermediate_dump_writer_test.cc | 1 + 7 files changed, 23 insertions(+), 2 deletions(-) diff --git a/client/ios_handler/in_process_handler.cc b/client/ios_handler/in_process_handler.cc index f13b140d58..92bb72e15b 100644 --- a/client/ios_handler/in_process_handler.cc +++ b/client/ios_handler/in_process_handler.cc @@ -62,6 +62,9 @@ namespace internal { InProcessHandler::InProcessHandler() = default; InProcessHandler::~InProcessHandler() { + if (cached_writer_) { + cached_writer_->Close(); + } UpdatePruneAndUploadThreads(false); } diff --git a/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/client/ios_handler/in_process_intermediate_dump_handler_test.cc index e61a604d9d..bccc930d34 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler_test.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler_test.cc @@ -49,6 +49,7 @@ class InProcessIntermediateDumpHandlerTest : public testing::Test { } void TearDown() override { + EXPECT_TRUE(writer_->Close()); writer_.reset(); EXPECT_FALSE(IsRegularFile(path_)); } diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 1a994bdb83..44473ccb07 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -61,6 +61,7 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } void TearDown() override { + EXPECT_TRUE(writer_->Close()); writer_.reset(); EXPECT_FALSE(IsRegularFile(path_)); } diff --git a/util/ios/ios_intermediate_dump_reader_test.cc b/util/ios/ios_intermediate_dump_reader_test.cc index a66d6c3d46..7dfecdf9a6 100644 --- a/util/ios/ios_intermediate_dump_reader_test.cc +++ b/util/ios/ios_intermediate_dump_reader_test.cc @@ -53,6 +53,7 @@ class IOSIntermediateDumpReaderTest : public testing::Test { } void TearDown() override { + ASSERT_TRUE(writer_->Close()); fd_.reset(); writer_.reset(); EXPECT_FALSE(IsRegularFile(path_)); diff --git a/util/ios/ios_intermediate_dump_writer.cc b/util/ios/ios_intermediate_dump_writer.cc index cd4d99d252..cd236dfaa6 100644 --- a/util/ios/ios_intermediate_dump_writer.cc +++ b/util/ios/ios_intermediate_dump_writer.cc @@ -17,6 +17,7 @@ #include #include +#include "base/check.h" #include "base/posix/eintr_wrapper.h" #include "build/build_config.h" #include "util/ios/raw_logging.h" @@ -50,6 +51,10 @@ bool RawLoggingCloseFile(int fd) { return rv == 0; } +IOSIntermediateDumpWriter::~IOSIntermediateDumpWriter() { + DCHECK_EQ(fd_, -1) << "Call Close() before this object is destroyed."; +} + bool IOSIntermediateDumpWriter::Open(const base::FilePath& path) { // Set data protection class D (No protection). A file with this type of // protection can be read from or written to at any time. @@ -71,7 +76,12 @@ bool IOSIntermediateDumpWriter::Open(const base::FilePath& path) { } bool IOSIntermediateDumpWriter::Close() { - return RawLoggingCloseFile(fd_); + if (fd_ < 0) { + return true; + } + int fd = fd_; + fd_ = -1; + return RawLoggingCloseFile(fd); } bool IOSIntermediateDumpWriter::ArrayMapStart() { diff --git a/util/ios/ios_intermediate_dump_writer.h b/util/ios/ios_intermediate_dump_writer.h index 836fbe7ac6..d4f7a7b770 100644 --- a/util/ios/ios_intermediate_dump_writer.h +++ b/util/ios/ios_intermediate_dump_writer.h @@ -39,12 +39,14 @@ namespace internal { //! Note: All methods are `RUNS-DURING-CRASH`. class IOSIntermediateDumpWriter final { public: - IOSIntermediateDumpWriter() = default; + IOSIntermediateDumpWriter() : fd_(-1) { } IOSIntermediateDumpWriter(const IOSIntermediateDumpWriter&) = delete; IOSIntermediateDumpWriter& operator=(const IOSIntermediateDumpWriter&) = delete; + ~IOSIntermediateDumpWriter(); + //! \brief Command instructions for the intermediate dump reader. enum class CommandType : uint8_t { //! \brief Indicates a new map, followed by associated key. @@ -73,6 +75,8 @@ class IOSIntermediateDumpWriter final { //! \brief Open and lock an intermediate dump file. This is the only method //! in the writer class that is generally run outside of a crash. //! + //! The client must invoke `Close()` before this object is destroyed. + //! //! \param[in] path The path to the intermediate dump. //! //! \return On success, returns `true`, otherwise returns `false`. diff --git a/util/ios/ios_intermediate_dump_writer_test.cc b/util/ios/ios_intermediate_dump_writer_test.cc index 24f56efd23..055ae70cca 100644 --- a/util/ios/ios_intermediate_dump_writer_test.cc +++ b/util/ios/ios_intermediate_dump_writer_test.cc @@ -41,6 +41,7 @@ class IOSIntermediateDumpWriterTest : public testing::Test { } void TearDown() override { + EXPECT_TRUE(writer_->Close()); writer_.reset(); EXPECT_EQ(unlink(path_.value().c_str()), 0) << ErrnoMessage("unlink"); } From 55de7bb48eee7dfd985bfff726b9ad4bc3084b6f Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 19 May 2022 14:36:49 -0600 Subject: [PATCH 170/478] [Crashpad/Annotations] Increase maximum annotation name length to 256 Crashpad annotation names are currently limited to 64 bytes. Breakpad supports up to 256 bytes, so for compatibility with existing clients, this increases the maximum annotation name size from 64 to 256 and adds new tests to confirm the maximum name and value sizes. Change-Id: Ib7954bea96046b6b7e18ed9743fe2a15dd3dabac Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3655975 Reviewed-by: Joshua Peraza Commit-Queue: Joshua Peraza Reviewed-by: Justin Cohen --- client/annotation.h | 3 +- .../module_snapshot_ios_intermediate_dump.cc | 14 ++- ...ess_snapshot_ios_intermediate_dump_test.cc | 104 ++++++++++++++---- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/client/annotation.h b/client/annotation.h index aa110bd670..9766fe7030 100644 --- a/client/annotation.h +++ b/client/annotation.h @@ -72,7 +72,8 @@ class AnnotationList; class Annotation { public: //! \brief The maximum length of an annotation’s name, in bytes. - static constexpr size_t kNameMaxLength = 64; + //! Matches the behavior of Breakpad's SimpleStringDictionary. + static constexpr size_t kNameMaxLength = 256; //! \brief The maximum size of an annotation’s value, in bytes. static constexpr size_t kValueMaxSize = 5 * 4096; diff --git a/snapshot/ios/module_snapshot_ios_intermediate_dump.cc b/snapshot/ios/module_snapshot_ios_intermediate_dump.cc index cdef7697ce..b7541b73b8 100644 --- a/snapshot/ios/module_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/module_snapshot_ios_intermediate_dump.cc @@ -19,6 +19,7 @@ #include "base/files/file_path.h" #include "base/mac/mach_logging.h" +#include "client/annotation.h" #include "snapshot/ios/intermediate_dump_reader_util.h" #include "util/ios/ios_intermediate_dump_data.h" #include "util/ios/ios_intermediate_dump_list.h" @@ -81,8 +82,11 @@ bool ModuleSnapshotIOSIntermediateDump::Initialize( std::string name; if (!GetDataStringFromMap( annotation.get(), Key::kAnnotationName, &name) || - name.empty() || name.length() > 64) { // Annotation::kNameMaxLength - LOG(ERROR) << "Invalid annotation name length."; + name.empty() || name.length() > Annotation::kNameMaxLength) { + LOG(ERROR) << "Invalid annotation name (" << name + << "), size=" << name.size() + << ", max size=" << Annotation::kNameMaxLength + << ", discarding annotation."; continue; } @@ -94,8 +98,10 @@ bool ModuleSnapshotIOSIntermediateDump::Initialize( if (type_dump && value_dump && type_dump->GetValue(&type)) { const std::vector& bytes = value_dump->bytes(); uint64_t length = bytes.size(); - if (!bytes.data() || length > 20480) { // Annotation::kValueMaxSize - LOG(ERROR) << "Invalid annotation value length."; + if (!bytes.data() || length > Annotation::kValueMaxSize) { + LOG(ERROR) << "Invalid annotation value, size=" << length + << ", max size=" << Annotation::kValueMaxSize + << ", discarding annotation."; continue; } annotation_objects_.push_back(AnnotationSnapshot(name, type, bytes)); diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 44473ccb07..34c34f80b1 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -51,7 +51,9 @@ class ReadToString : public crashpad::MemorySnapshot::Delegate { class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { protected: - // testing::Test: + ProcessSnapshotIOSIntermediateDumpTest() + : long_annotation_name_(Annotation::kNameMaxLength, 'a'), + long_annotation_value_(Annotation::kValueMaxSize, 'b') {} void SetUp() override { path_ = temp_dir_.path().Append("dump_file"); @@ -159,9 +161,16 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } } - void WriteAnnotations(IOSIntermediateDumpWriter* writer) { - constexpr char annotation_name[] = "annotation_name"; - constexpr char annotation_value[] = "annotation_value"; + void WriteAnnotations(IOSIntermediateDumpWriter* writer, + bool use_long_annotations) { + constexpr char short_annotation_name[] = "annotation_name"; + constexpr char short_annotation_value[] = "annotation_value"; + const char* const annotation_name = use_long_annotations + ? long_annotation_name_.c_str() + : short_annotation_name; + const char* const annotation_value = use_long_annotations + ? long_annotation_value_.c_str() + : short_annotation_value; { IOSIntermediateDumpWriter::ScopedArray annotationObjectArray( writer, Key::kAnnotationObjects); @@ -199,7 +208,9 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } } - void WriteModules(IOSIntermediateDumpWriter* writer, bool has_module_path) { + void WriteModules(IOSIntermediateDumpWriter* writer, + bool has_module_path, + bool use_long_annotations) { IOSIntermediateDumpWriter::ScopedArray moduleArray(writer, Key::kModules); for (uint32_t image_index = 0; image_index < 2; ++image_index) { IOSIntermediateDumpWriter::ScopedArrayMap modules(writer); @@ -240,12 +251,13 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { EXPECT_TRUE(writer->AddProperty(Key::kSourceVersion, &source_version)); EXPECT_TRUE(writer->AddProperty(Key::kUUID, &uuid)); EXPECT_TRUE(writer->AddProperty(Key::kFileType, &filetype)); - WriteAnnotations(writer); + WriteAnnotations(writer, use_long_annotations); } } void ExpectModules(const std::vector& modules, - bool expect_module_path) { + bool expect_module_path, + bool expect_long_annotations) { for (auto module : modules) { EXPECT_EQ(module->GetModuleType(), ModuleSnapshot::kModuleTypeSharedLibrary); @@ -260,22 +272,39 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { EXPECT_EQ(uuid.ToString(), "00010203-0405-0607-0809-0a0b0c0d0e0f"); for (auto annotation : module->AnnotationsVector()) { - EXPECT_STREQ(annotation.c_str(), "annotation_value"); + if (expect_long_annotations) { + EXPECT_EQ(annotation, long_annotation_value_); + } else { + EXPECT_STREQ(annotation.c_str(), "annotation_value"); + } } for (const auto& it : module->AnnotationsSimpleMap()) { - EXPECT_STREQ(it.first.c_str(), "annotation_name"); - EXPECT_STREQ(it.second.c_str(), "annotation_value"); + if (expect_long_annotations) { + EXPECT_EQ(it.first, long_annotation_name_); + EXPECT_EQ(it.second, long_annotation_value_); + } else { + EXPECT_STREQ(it.first.c_str(), "annotation_name"); + EXPECT_STREQ(it.second.c_str(), "annotation_value"); + } } for (auto annotation_object : module->AnnotationObjects()) { - EXPECT_STREQ(annotation_object.name.c_str(), "annotation_name"); EXPECT_EQ(annotation_object.type, (short)Annotation::Type::kString); - EXPECT_STREQ(std::string(reinterpret_cast( - annotation_object.value.data()), - annotation_object.value.size()) - .c_str(), - "annotation_value"); + if (expect_long_annotations) { + EXPECT_EQ(annotation_object.name, long_annotation_name_); + EXPECT_EQ(std::string(reinterpret_cast( + annotation_object.value.data()), + annotation_object.value.size()), + long_annotation_value_); + } else { + EXPECT_STREQ(annotation_object.name.c_str(), "annotation_name"); + EXPECT_STREQ(std::string(reinterpret_cast( + annotation_object.value.data()), + annotation_object.value.size()) + .c_str(), + "annotation_value"); + } } } } @@ -432,7 +461,8 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } void ExpectSnapshot(const ProcessSnapshot& snapshot, - bool expect_module_path) { + bool expect_module_path, + bool expect_long_annotations) { EXPECT_EQ(snapshot.ProcessID(), 2); EXPECT_EQ(snapshot.ParentProcessID(), 1); @@ -455,7 +485,8 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { ExpectSystem(*snapshot.System()); ExpectThreads(snapshot.Threads()); - ExpectModules(snapshot.Modules(), expect_module_path); + ExpectModules( + snapshot.Modules(), expect_module_path, expect_long_annotations); ExpectMachException(*snapshot.Exception()); } @@ -464,6 +495,8 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { ScopedTempDir temp_dir_; base::FilePath path_; std::map annotations_; + const std::string long_annotation_name_; + const std::string long_annotation_value_; }; TEST_F(ProcessSnapshotIOSIntermediateDumpTest, InitializeNoFile) { @@ -634,14 +667,38 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, ShortContext) { WriteSystemInfo(writer()); WriteProcessInfo(writer()); WriteThreads(writer()); - WriteModules(writer(), /*has_module_path=*/false); + WriteModules( + writer(), /*has_module_path=*/false, /*use_long_annotations=*/false); WriteMachException(writer(), true /* short_context=true*/); } ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); EXPECT_TRUE(DumpSnapshot(process_snapshot)); - ExpectSnapshot(process_snapshot, /*expect_module_path=*/false); + ExpectSnapshot(process_snapshot, + /*expect_module_path=*/false, + /*expect_long_annotations=*/false); +} + +TEST_F(ProcessSnapshotIOSIntermediateDumpTest, LongAnnotations) { + { + IOSIntermediateDumpWriter::ScopedRootMap rootMap(writer()); + uint8_t version = 1; + EXPECT_TRUE(writer()->AddProperty(Key::kVersion, &version)); + WriteSystemInfo(writer()); + WriteProcessInfo(writer()); + WriteThreads(writer()); + WriteModules( + writer(), /*has_module_path=*/false, /*use_long_annotations=*/true); + WriteMachException(writer()); + } + ProcessSnapshotIOSIntermediateDump process_snapshot; + ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); + EXPECT_FALSE(IsRegularFile(path())); + EXPECT_TRUE(DumpSnapshot(process_snapshot)); + ExpectSnapshot(process_snapshot, + /*expect_module_path=*/false, + /*expect_long_annotations=*/true); } TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) { @@ -652,14 +709,17 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) { WriteSystemInfo(writer()); WriteProcessInfo(writer()); WriteThreads(writer()); - WriteModules(writer(), /*has_module_path=*/true); + WriteModules( + writer(), /*has_module_path=*/true, /*use_long_annotations=*/false); WriteMachException(writer()); } ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); EXPECT_TRUE(DumpSnapshot(process_snapshot)); - ExpectSnapshot(process_snapshot, /*expect_module_path=*/true); + ExpectSnapshot(process_snapshot, + /*expect_module_path=*/true, + /*expect_long_annotations=*/false); } TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FuzzTestCases) { From c5094b99a4e41e1c70215aba7fed5624b69ca81e Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 20 May 2022 09:05:48 -0400 Subject: [PATCH 171/478] minidump: Size the annotation list writer iovec more carefully https://chromium-review.googlesource.com/c/crashpad/crashpad/+/731309/6#message-19ebbbfb10fa499bb00989728b19756982641326 Change-Id: I274eb62bdc9b0039196dc01902eb8654154a8c1a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3654638 Commit-Queue: Mark Mentovai Reviewed-by: Robert Sesek --- minidump/minidump_annotation_writer.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/minidump/minidump_annotation_writer.cc b/minidump/minidump_annotation_writer.cc index 54a3ecba16..8a62eccb81 100644 --- a/minidump/minidump_annotation_writer.cc +++ b/minidump/minidump_annotation_writer.cc @@ -147,9 +147,10 @@ bool MinidumpAnnotationListWriter::WriteObject( FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); - std::vector iov(1 + objects_.size()); - iov[0].iov_base = minidump_list_.get(); - iov[0].iov_len = sizeof(*minidump_list_); + std::vector iov; + iov.reserve(1 + objects_.size()); + iov.emplace_back( + WritableIoVec{minidump_list_.get(), sizeof(*minidump_list_)}); for (const auto& object : objects_) { iov.emplace_back(WritableIoVec{object->minidump_annotation(), From 13a1e171eb0787de938467f1d6cbeec7954dfc5f Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Sat, 21 May 2022 16:18:10 +0000 Subject: [PATCH 172/478] C++20 build fixes. * ATOMIC_FLAG_INIT is deprecated. * Compound ops on volatiles are deprecated. Bug: chromium:1284275 Change-Id: I2235662c00e4be8c5eba2aaf565663faf8d9576a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3658639 Commit-Queue: Peter Kasting Reviewed-by: Mark Mentovai --- client/crashpad_client_linux.cc | 5 +++++ util/posix/signals_test.cc | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 53c2dadac9..295ec1615d 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -253,7 +253,12 @@ class SignalHandler { ExceptionInformation exception_information_ = {}; CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; int32_t dump_done_futex_ = kDumpNotDone; +#if !defined(__cpp_lib_atomic_value_initialization) || \ + __cpp_lib_atomic_value_initialization < 201911L std::atomic_flag disabled_ = ATOMIC_FLAG_INIT; +#else + std::atomic_flag disabled_; +#endif static SignalHandler* handler_; }; diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index 94d8e51153..9ccd4c5926 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -166,7 +166,7 @@ void CauseSignal(int sig, int code) { #if defined(ARCH_CPU_X86_FAMILY) [[maybe_unused]] volatile int a = 42; volatile int b = 0; - a /= b; + a = a / b; #endif break; } From 5f2a706f71de3204c916401f3ea084e47f689057 Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Sun, 22 May 2022 15:08:03 +0000 Subject: [PATCH 173/478] Blind attempt to fix compile failure in latest roll. Bug: none Change-Id: Iea44283cf4df029b595e87bb42b57422e310e7a4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3659054 Reviewed-by: Mark Mentovai Commit-Queue: Peter Kasting --- util/ios/ios_intermediate_dump_writer.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/ios/ios_intermediate_dump_writer.cc b/util/ios/ios_intermediate_dump_writer.cc index cd236dfaa6..0fd3851697 100644 --- a/util/ios/ios_intermediate_dump_writer.cc +++ b/util/ios/ios_intermediate_dump_writer.cc @@ -17,6 +17,8 @@ #include #include +#include + #include "base/check.h" #include "base/posix/eintr_wrapper.h" #include "build/build_config.h" From b1ffe935626d6760cdc4df83dbf5ef5238ce4473 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Tue, 24 May 2022 10:26:22 -0600 Subject: [PATCH 174/478] [ios] Fix two shutdown races There were two shutdown races in the iOS Crashpad client: 1) MachMessageServer::Run can return either MACH_RCV_PORT_CHANGED *or* MACH_RCV_INVALID_NAME based on the timing of when the port is closed, for example: https://github.com/mattgallagher/CwlPreconditionTesting/blob/c21f7bab5ca8eee0a9998bbd17ca1d0eb45d4688/Sources/CwlPreconditionTesting/CwlCatchBadInstruction.swift#L131 2) The iOS crashpad::CrashHandler thread could read from its member variable mach_handler_running_ while another thread wrote to it Change-Id: I696ece8575d9b88cbd0593e7c479bd4c7f863f45 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3651395 Reviewed-by: Justin Cohen Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- client/crashpad_client_ios.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 2a737f3ccb..f40a8c76f1 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -219,9 +220,19 @@ class CrashHandler : public Thread, MachMessageServer::kPersistent, MachMessageServer::kReceiveLargeIgnore, kMachMessageTimeoutWaitIndefinitely); - MACH_CHECK(mr == (mach_handler_running_ ? MACH_SEND_INVALID_DEST - : MACH_RCV_PORT_CHANGED), - mr) + MACH_CHECK( + mach_handler_running_ + ? mr == MACH_SEND_INVALID_DEST // This shouldn't happen for + // exception messages that come + // from the kernel itself, but if + // something else in-process sends + // exception messages and breaks, + // handle that case. + : (mr == MACH_RCV_PORT_CHANGED || // Port was closed while the + // thread was listening. + mr == MACH_RCV_INVALID_NAME), // Port was closed before the + // thread started listening. + mr) << "MachMessageServer::Run"; } } @@ -384,7 +395,7 @@ class CrashHandler : public Thread, struct sigaction old_action_ = {}; internal::InProcessHandler in_process_handler_; static CrashHandler* instance_; - bool mach_handler_running_ = false; + std::atomic mach_handler_running_ = false; InitializationStateDcheck initialized_; }; From 21d03eec9750c67f769ab7c14fcedc9dd9c38d01 Mon Sep 17 00:00:00 2001 From: Anton Siluanov Date: Wed, 1 Jun 2022 10:42:13 +0300 Subject: [PATCH 175/478] Fix attachments name instead of ignoring with error (#67) Co-authored-by: Anton Syluanov --- client/crash_report_database.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index 7a3732b8d8..f3e3d53f91 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -28,12 +28,13 @@ namespace { constexpr base::FilePath::CharType kAttachmentsDirectory[] = FILE_PATH_LITERAL("attachments"); -bool AttachmentNameIsOK(const std::string& name) { - for (const char c : name) { - if (c != '_' && c != '-' && c != '.' && !isalnum(c)) - return false; - } - return true; +std::string FixAttachmentName(std::string name) { + std::replace_if(name.begin(), name.end(), [&](char c) + { + return c != '_' && c != '-' && c != '.' && !isalnum(c); + }, '_'); + + return name; } } // namespace @@ -94,19 +95,15 @@ FileReaderInterface* CrashReportDatabase::NewReport::Reader() { FileWriter* CrashReportDatabase::NewReport::AddAttachment( const std::string& name) { - if (!AttachmentNameIsOK(name)) { - LOG(ERROR) << "invalid name for attachment " << name; - return nullptr; - } base::FilePath report_attachments_dir = database_->AttachmentsPath(uuid_); if (!LoggingCreateDirectory( report_attachments_dir, FilePermissions::kOwnerOnly, true)) { return nullptr; } #if BUILDFLAG(IS_WIN) - const std::wstring name_string = base::UTF8ToWide(name); + const std::wstring name_string = base::UTF8ToWide(FixAttachmentName(name)); #else - const std::string name_string = name; + const std::string name_string = FixAttachmentName(name); #endif base::FilePath attachment_path = report_attachments_dir.Append(name_string); auto writer = std::make_unique(); From a903f7541f4438cd3005b2ecbf8adcf3155b4334 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Tue, 31 May 2022 11:21:19 -0600 Subject: [PATCH 176/478] [minidump] Add support for RVA64 / MINIDUMP_LOCATION_DESCRIPTOR64 Newer minidump stream types, like MINIDUMP_THREAD_NAME_LIST, use 64-bit RVAs (which have 64-bit location descriptors) instead of 32-bit RVAs and location descriptors. This adds support to MinidumpWritable for the new 64-bit RVA64 and MINIDUMP_LOCATION_DESCRIPTOR64 types. Bug: crashpad:327 Change-Id: Icd67bca600756a68ef9ba7d5a429f935eebf726f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3673776 Commit-Queue: Ben Hamilton Reviewed-by: Joshua Peraza --- compat/non_win/dbghelp.h | 19 +++ minidump/minidump_writable.cc | 71 +++++++-- minidump/minidump_writable.h | 13 ++ minidump/minidump_writable_test.cc | 237 ++++++++++++++++++++--------- 4 files changed, 254 insertions(+), 86 deletions(-) diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 1f8013531b..0618b91533 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -42,6 +42,15 @@ //! \sa MINIDUMP_LOCATION_DESCRIPTOR typedef uint32_t RVA; +//! \brief A 64-bit offset within a minidump file, relative to the start of its +//! MINIDUMP_HEADER. +//! +//! RVA stands for “relative virtual address”. Within a minidump file, RVAs are +//! used as pointers to link structures together. +//! +//! \sa MINIDUMP_LOCATION_DESCRIPTOR64 +typedef uint64_t RVA64; + //! \brief A pointer to a structure or union within a minidump file. struct __attribute__((packed, aligned(4))) MINIDUMP_LOCATION_DESCRIPTOR { //! \brief The size of the referenced structure or union, in bytes. @@ -52,6 +61,16 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_LOCATION_DESCRIPTOR { RVA Rva; }; +//! \brief A 64-bit pointer to a structure or union within a minidump file. +struct __attribute__((packed, aligned(4))) MINIDUMP_LOCATION_DESCRIPTOR64 { + //! \brief The size of the referenced structure or union, in bytes. + uint64_t DataSize; + + //! \brief The 64-bit relative virtual address of the structure or union + //! within the minidump file. + RVA64 Rva; +}; + //! \brief A pointer to a snapshot of a region of memory contained within a //! minidump file. //! diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index 9bfba52e08..e1d23bd7a3 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -75,6 +75,12 @@ void MinidumpWritable::RegisterRVA(RVA* rva) { registered_rvas_.push_back(rva); } +void MinidumpWritable::RegisterRVA(RVA64* rva64) { + DCHECK_LE(state_, kStateFrozen); + + registered_rva64s_.push_back(rva64); +} + void MinidumpWritable::RegisterLocationDescriptor( MINIDUMP_LOCATION_DESCRIPTOR* location_descriptor) { DCHECK_LE(state_, kStateFrozen); @@ -82,12 +88,20 @@ void MinidumpWritable::RegisterLocationDescriptor( registered_location_descriptors_.push_back(location_descriptor); } +void MinidumpWritable::RegisterLocationDescriptor( + MINIDUMP_LOCATION_DESCRIPTOR64* location_descriptor64) { + DCHECK_LE(state_, kStateFrozen); + + registered_location_descriptor64s_.push_back(location_descriptor64); +} + MinidumpWritable::MinidumpWritable() : registered_rvas_(), + registered_rva64s_(), registered_location_descriptors_(), + registered_location_descriptor64s_(), leading_pad_bytes_(0), - state_(kStateMutable) { -} + state_(kStateMutable) {} bool MinidumpWritable::Freeze() { DCHECK_EQ(state_, kStateMutable); @@ -160,10 +174,10 @@ size_t MinidumpWritable::WillWriteAtOffset( return kInvalidSize; } - // Populate the RVA fields in other objects that have registered to point to - // this one. Typically, a parent object will have registered to point to its - // children, but this can also occur where no parent-child relationship - // exists. + // Populate the 32-bit RVA fields in other objects that have registered to + // point to this one. Typically, a parent object will have registered to + // point to its children, but this can also occur where no parent-child + // relationship exists. if (!registered_rvas_.empty() || !registered_location_descriptors_.empty()) { RVA local_rva; @@ -191,12 +205,45 @@ size_t MinidumpWritable::WillWriteAtOffset( } } - // This object is now considered writable. However, if it contains RVA or - // MINIDUMP_LOCATION_DESCRIPTOR fields, they may not be fully updated yet, - // because it’s the repsonsibility of these fields’ pointees to update them. - // Once WillWriteAtOffset has completed running for both phases on an entire - // tree, and the entire tree has moved into kStateFrozen, all RVA and - // MINIDUMP_LOCATION_DESCRIPTOR fields within that tree will be populated. + // Populate the 64-bit RVA fields in other objects that have registered to + // point to this one. Typically, a parent object will have registered to + // point to its children, but this can also occur where no parent-child + // relationship exists. + if (!registered_rva64s_.empty() || + !registered_location_descriptor64s_.empty()) { + RVA64 local_rva64; + if (!AssignIfInRange(&local_rva64, local_offset)) { + LOG(ERROR) << "offset " << local_offset << " out of range"; + return kInvalidSize; + } + + for (RVA64* rva64 : registered_rva64s_) { + *rva64 = local_rva64; + } + + if (!registered_location_descriptor64s_.empty()) { + decltype(registered_location_descriptor64s_[0]->DataSize) local_size; + if (!AssignIfInRange(&local_size, size)) { + LOG(ERROR) << "size " << size << " out of range"; + return kInvalidSize; + } + + for (MINIDUMP_LOCATION_DESCRIPTOR64* location_descriptor : + registered_location_descriptor64s_) { + location_descriptor->DataSize = local_size; + location_descriptor->Rva = local_rva64; + } + } + } + + // This object is now considered writable. However, if it contains RVA/RVA64 + // or MINIDUMP_LOCATION_DESCRIPTOR/MINIDUMP_LOCATION_DESCRIPTOR64 fields, + // they may not be fully updated yet, because it’s the repsonsibility of + // these fields’ pointees to update them. Once WillWriteAtOffset has + // completed running for both phases on an entire tree, and the entire tree + // has moved into kStateFrozen, all RVA/RVA64 and + // MINIDUMP_LOCATION_DESCRIPTOR/MINIDUMP_LOCATION_DESCRIPTOR64 fields within + // that tree will be populated. state_ = kStateWritable; } else { if (phase == kPhaseEarly) { diff --git a/minidump/minidump_writable.h b/minidump/minidump_writable.h index bc36cb5c05..284b9f0799 100644 --- a/minidump/minidump_writable.h +++ b/minidump/minidump_writable.h @@ -71,6 +71,9 @@ class MinidumpWritable { // to be able to register their own pointers with distinct objects. void RegisterRVA(RVA* rva); + //! \brief 64-bit specialization of RegisterRVA. + void RegisterRVA(RVA64* rva); + //! \brief Registers a location descriptor as one that should point to the //! object on which this method is called. //! @@ -89,6 +92,10 @@ class MinidumpWritable { void RegisterLocationDescriptor( MINIDUMP_LOCATION_DESCRIPTOR* location_descriptor); + //! \brief 64-bit specialization of RegisterLocationDescriptor. + void RegisterLocationDescriptor( + MINIDUMP_LOCATION_DESCRIPTOR64* location_descriptor64); + protected: //! \brief Identifies the state of an object. //! @@ -267,9 +274,15 @@ class MinidumpWritable { private: std::vector registered_rvas_; // weak + std::vector registered_rva64s_; // weak + // weak std::vector registered_location_descriptors_; + // weak + std::vector + registered_location_descriptor64s_; + size_t leading_pad_bytes_; State state_; }; diff --git a/minidump/minidump_writable_test.cc b/minidump/minidump_writable_test.cc index ef34e54225..2032b06363 100644 --- a/minidump/minidump_writable_test.cc +++ b/minidump/minidump_writable_test.cc @@ -485,14 +485,15 @@ TEST(MinidumpWritable, MinidumpWritable) { } } -class TestRVAMinidumpWritable final : public BaseTestMinidumpWritable { +template +class TTestRVAMinidumpWritable final : public BaseTestMinidumpWritable { public: - TestRVAMinidumpWritable() : BaseTestMinidumpWritable(), rva_() {} + TTestRVAMinidumpWritable() : BaseTestMinidumpWritable(), rva_() {} - TestRVAMinidumpWritable(const TestRVAMinidumpWritable&) = delete; - TestRVAMinidumpWritable& operator=(const TestRVAMinidumpWritable&) = delete; + TTestRVAMinidumpWritable(const TTestRVAMinidumpWritable&) = delete; + TTestRVAMinidumpWritable& operator=(const TTestRVAMinidumpWritable&) = delete; - ~TestRVAMinidumpWritable() {} + ~TTestRVAMinidumpWritable() {} void SetRVA(MinidumpWritable* other) { other->RegisterRVA(&rva_); } @@ -509,15 +510,46 @@ class TestRVAMinidumpWritable final : public BaseTestMinidumpWritable { } private: - RVA rva_; + RVAType rva_; }; -RVA RVAAtIndex(const std::string& string, size_t index) { - return *reinterpret_cast(&string[index * sizeof(RVA)]); +template +RVAType TRVAAtIndex(const std::string& string, size_t index) { + return *reinterpret_cast(&string[index * sizeof(RVAType)]); } -TEST(MinidumpWritable, RVA) { +template +struct TestNames {}; + +template <> +struct TestNames { + static constexpr char kName[] = "RVA"; +}; + +template <> +struct TestNames { + static constexpr char kName[] = "RVA64"; +}; + +class TestTypeNames { + public: + template + static std::string GetName(int) { + return std::string(TestNames::kName); + } +}; + +template +class MinidumpWritable : public ::testing::Test {}; + +using RVATypes = ::testing::Types; +TYPED_TEST_SUITE(MinidumpWritable, RVATypes, TestTypeNames); + +TYPED_TEST(MinidumpWritable, RVA) { StringFile string_file; + using TestRVAMinidumpWritable = TTestRVAMinidumpWritable; + const auto RVAAtIndex = TRVAAtIndex; + constexpr size_t kRVASize = sizeof(TypeParam); { SCOPED_TRACE("unset"); @@ -525,8 +557,8 @@ TEST(MinidumpWritable, RVA) { TestRVAMinidumpWritable rva_writable; EXPECT_TRUE(rva_writable.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * kRVASize); rva_writable.Verify(); } @@ -537,8 +569,8 @@ TEST(MinidumpWritable, RVA) { rva_writable.SetRVA(&rva_writable); EXPECT_TRUE(rva_writable.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * kRVASize); rva_writable.Verify(); } @@ -552,9 +584,9 @@ TEST(MinidumpWritable, RVA) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 2 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 1 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), 2 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 0 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 1 * kRVASize); parent.Verify(); } @@ -567,9 +599,9 @@ TEST(MinidumpWritable, RVA) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 2 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), 2 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * kRVASize); parent.Verify(); } @@ -583,9 +615,9 @@ TEST(MinidumpWritable, RVA) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 2 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), 2 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * kRVASize); parent.Verify(); } @@ -607,28 +639,29 @@ TEST(MinidumpWritable, RVA) { child.AddChild(&grandchild_2); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 5 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 2), 1 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 3), 1 * sizeof(RVA)); - EXPECT_EQ(RVAAtIndex(string_file.string(), 4), 1 * sizeof(RVA)); + ASSERT_EQ(string_file.string().size(), 5 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 0), 1 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 1), 0 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 2), 1 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 3), 1 * kRVASize); + EXPECT_EQ(RVAAtIndex(string_file.string(), 4), 1 * kRVASize); parent.Verify(); } } -class TestLocationDescriptorMinidumpWritable final +template +class TTestLocationDescriptorMinidumpWritable final : public BaseTestMinidumpWritable { public: - TestLocationDescriptorMinidumpWritable() + TTestLocationDescriptorMinidumpWritable() : BaseTestMinidumpWritable(), location_descriptor_(), string_() {} - TestLocationDescriptorMinidumpWritable( - const TestLocationDescriptorMinidumpWritable&) = delete; - TestLocationDescriptorMinidumpWritable& operator=( - const TestLocationDescriptorMinidumpWritable&) = delete; + TTestLocationDescriptorMinidumpWritable( + const TTestLocationDescriptorMinidumpWritable&) = delete; + TTestLocationDescriptorMinidumpWritable& operator=( + const TTestLocationDescriptorMinidumpWritable&) = delete; - ~TestLocationDescriptorMinidumpWritable() {} + ~TTestLocationDescriptorMinidumpWritable() {} void SetLocationDescriptor(MinidumpWritable* other) { other->RegisterLocationDescriptor(&location_descriptor_); @@ -658,30 +691,61 @@ class TestLocationDescriptorMinidumpWritable final } private: - MINIDUMP_LOCATION_DESCRIPTOR location_descriptor_; + MinidumpLocationDescriptorType location_descriptor_; std::string string_; }; -struct LocationDescriptorAndData { - MINIDUMP_LOCATION_DESCRIPTOR location_descriptor; +template +struct TLocationDescriptorAndData { + MinidumpLocationDescriptorType location_descriptor; char string[1]; }; -const LocationDescriptorAndData* LDDAtIndex(const std::string& string, - size_t index) { - return reinterpret_cast(&string[index]); +template +const TLocationDescriptorAndData* TLDDAtIndex( + const std::string& string, + size_t index) { + return reinterpret_cast< + const TLocationDescriptorAndData*>( + &string[index]); } -TEST(MinidumpWritable, LocationDescriptor) { +template +class MinidumpWritableLocationDescriptor : public ::testing::Test {}; + +template <> +struct TestNames { + static constexpr char kName[] = "MINIDUMP_LOCATION_DESCRIPTOR"; +}; + +template <> +struct TestNames { + static constexpr char kName[] = "MINIDUMP_LOCATION_DESCRIPTOR64"; +}; + +using MinidumpLocationDescriptorTypes = + ::testing::Types; +TYPED_TEST_SUITE(MinidumpWritableLocationDescriptor, + MinidumpLocationDescriptorTypes, + TestTypeNames); + +TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { StringFile string_file; + using LocationDescriptorAndData = TLocationDescriptorAndData; + const auto LDDAtIndex = TLDDAtIndex; + using TestLocationDescriptorMinidumpWritable = + TTestLocationDescriptorMinidumpWritable; + constexpr size_t kMinidumpLocationDescriptorSize = sizeof(TypeParam); + { SCOPED_TRACE("unset"); string_file.Reset(); TestLocationDescriptorMinidumpWritable location_descriptor_writable; EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 9u); + ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 1); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); @@ -696,9 +760,10 @@ TEST(MinidumpWritable, LocationDescriptor) { &location_descriptor_writable); EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 9u); + ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 1); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 9u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 1); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); location_descriptor_writable.Verify(); } @@ -712,9 +777,10 @@ TEST(MinidumpWritable, LocationDescriptor) { location_descriptor_writable.SetString("zz"); EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 11u); + ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 3); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 11u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 3); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); EXPECT_STREQ("zz", ldd->string); location_descriptor_writable.Verify(); @@ -732,14 +798,18 @@ TEST(MinidumpWritable, LocationDescriptor) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 22u); + ASSERT_EQ(string_file.string().size(), + kMinidumpLocationDescriptorSize * 2 + 6); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 11u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 3); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); EXPECT_STREQ("yy", ldd->string); - ldd = LDDAtIndex(string_file.string(), 12); - EXPECT_EQ(ldd->location_descriptor.DataSize, 10u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 2); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("x", ldd->string); parent.Verify(); } @@ -755,12 +825,15 @@ TEST(MinidumpWritable, LocationDescriptor) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 23u); + ASSERT_EQ(string_file.string().size(), + kMinidumpLocationDescriptorSize * 2 + 7); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 11u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 3); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("www", ldd->string); - ldd = LDDAtIndex(string_file.string(), 12); + ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); EXPECT_STREQ("vv", ldd->string); @@ -779,13 +852,17 @@ TEST(MinidumpWritable, LocationDescriptor) { parent.AddChild(&child); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 29u); + ASSERT_EQ(string_file.string().size(), + kMinidumpLocationDescriptorSize * 2 + 13); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 13u); - EXPECT_EQ(ldd->location_descriptor.Rva, 16u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 5); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 8); EXPECT_STREQ("uuuu", ldd->string); - ldd = LDDAtIndex(string_file.string(), 16); - EXPECT_EQ(ldd->location_descriptor.DataSize, 13u); + ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 8); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 5); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); EXPECT_STREQ("tttt", ldd->string); parent.Verify(); @@ -814,26 +891,38 @@ TEST(MinidumpWritable, LocationDescriptor) { child.AddChild(&grandchild_2); EXPECT_TRUE(parent.WriteEverything(&string_file)); - ASSERT_EQ(string_file.string().size(), 58u); + ASSERT_EQ(string_file.string().size(), + kMinidumpLocationDescriptorSize * 5 + 18); const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 10u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 2); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("s", ldd->string); - ldd = LDDAtIndex(string_file.string(), 12); + ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); EXPECT_EQ(ldd->location_descriptor.Rva, 0u); EXPECT_STREQ("r", ldd->string); - ldd = LDDAtIndex(string_file.string(), 24); - EXPECT_EQ(ldd->location_descriptor.DataSize, 10u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + ldd = LDDAtIndex(string_file.string(), + kMinidumpLocationDescriptorSize * 2 + 8); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 2); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("q", ldd->string); - ldd = LDDAtIndex(string_file.string(), 36); - EXPECT_EQ(ldd->location_descriptor.DataSize, 10u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + ldd = LDDAtIndex(string_file.string(), + kMinidumpLocationDescriptorSize * 3 + 12); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 2); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("p", ldd->string); - ldd = LDDAtIndex(string_file.string(), 48); - EXPECT_EQ(ldd->location_descriptor.DataSize, 10u); - EXPECT_EQ(ldd->location_descriptor.Rva, 12u); + ldd = LDDAtIndex(string_file.string(), + kMinidumpLocationDescriptorSize * 4 + 16); + EXPECT_EQ(ldd->location_descriptor.DataSize, + kMinidumpLocationDescriptorSize + 2); + EXPECT_EQ(ldd->location_descriptor.Rva, + kMinidumpLocationDescriptorSize + 4); EXPECT_STREQ("o", ldd->string); parent.Verify(); } From fc0b157a8e9f1680ada5f59473fbac3965a70e50 Mon Sep 17 00:00:00 2001 From: Alex Pankhurst Date: Thu, 2 Jun 2022 10:25:00 -0700 Subject: [PATCH 177/478] [fuchsia] Fix build errors on Fuchsia Fuchsia's Crashpad roller was failing due to 'std::size' not being found and struct fields not being initialized (detected by -Wmissing-field-initializers) - Fix 'std::size' issue by using a std::array instead of a plain C array - Fix missing initializers with default values Bug: fxbug.dev/101498 Change-Id: I75fa54d5c1730772b1af1be31c64b0cc58886a90 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3687239 Commit-Queue: Alex Pankhurst Reviewed-by: Joshua Peraza --- client/crash_report_database_mac.mm | 7 ++++--- minidump/minidump_context_writer.cc | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index c6abe8aaa6..9095392307 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -57,7 +58,7 @@ constexpr char kSettings[] = "settings.dat"; -constexpr const char* kReportDirectories[] = { +constexpr std::array kReportDirectories = { kWriteDirectory, kUploadPendingDirectory, kCompletedDirectory, @@ -291,8 +292,8 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, } // Create the three processing directories for the database. - for (size_t i = 0; i < std::size(kReportDirectories); ++i) { - if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) + for (const auto& dir : kReportDirectories) { + if (!CreateOrEnsureDirectoryExists(base_dir_.Append(dir))) return false; } diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index 6ae25b8fe1..bf02c1bd28 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -131,7 +131,6 @@ MinidumpContextX86Writer::MinidumpContextX86Writer() MinidumpContextX86Writer::~MinidumpContextX86Writer() { } - void MinidumpContextX86Writer::InitializeFromSnapshot( const CPUContextX86* context_snapshot) { DCHECK_EQ(state(), kStateMutable); @@ -288,8 +287,8 @@ bool MinidumpContextAMD64Writer::WriteObject(FileWriterInterface* file_writer) { memcpy(buf, &context_, sizeof(context_)); if (xsave_entries_.size() > 0) { - MinidumpContextExHeader context_ex = {{0}, {0}, {0}}; - MinidumpXSaveAreaHeader xsave_header = {0}; + MinidumpContextExHeader context_ex = {{0, 0}, {0, 0}, {0, 0}}; + MinidumpXSaveAreaHeader xsave_header = {0, 0, {}}; // CONTEXT_EX goes directly after the CONTEXT. |offset| is relative to // &CONTEXT_EX. From 91cec09d9301048d2c65b33ad4677f273d9f257c Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 2 Jun 2022 12:27:37 -0600 Subject: [PATCH 178/478] [minidump] Extend minidump string writer support for RVA64 strings To support MINIDUMP_THREAD_NAME_LIST (which uses 64-bit RVAs for the thread name MINIDUMP_STRING), this adds minidump string writing and reading support for the new 64-bit RVA64 and MINIDUMP_LOCATION_DESCRIPTOR64 types. Bug: crashpad:327 Change-Id: Iffefffef358517dfc6deac02051dff9dbb8eb214 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3673779 Reviewed-by: Joshua Peraza Commit-Queue: Ben Hamilton --- minidump/minidump_context_writer_test.cc | 109 +++++++++++------- minidump/minidump_string_writer_test.cc | 59 +++++++--- .../test/minidump_string_writer_test_util.cc | 73 ++++++++++-- .../test/minidump_string_writer_test_util.h | 22 ++++ minidump/test/minidump_writable_test_util.cc | 49 ++++++-- minidump/test/minidump_writable_test_util.h | 44 +++++++ snapshot/minidump/minidump_string_reader.cc | 32 ++++- snapshot/minidump/minidump_string_reader.h | 17 +++ 8 files changed, 325 insertions(+), 80 deletions(-) diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc index b4bfdbdb64..f52d9baeb6 100644 --- a/minidump/minidump_context_writer_test.cc +++ b/minidump/minidump_context_writer_test.cc @@ -16,6 +16,10 @@ #include +#include +#include + +#include "base/notreached.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "minidump/test/minidump_context_test_util.h" @@ -28,7 +32,7 @@ namespace crashpad { namespace test { namespace { -template +template void EmptyContextTest(void (*expect_context)(uint32_t, const Context*, bool)) { Writer context_writer; StringFile string_file; @@ -36,13 +40,34 @@ void EmptyContextTest(void (*expect_context)(uint32_t, const Context*, bool)) { ASSERT_EQ(string_file.string().size(), sizeof(Context)); const Context* observed = - MinidumpWritableAtRVA(string_file.string(), 0); + MinidumpWritableAtRVA(string_file.string(), RVAType(0)); ASSERT_TRUE(observed); expect_context(0, observed, false); } -TEST(MinidumpContextWriter, MinidumpContextX86Writer) { +class TestTypeNames { + public: + template + static std::string GetName(int) { + if (std::is_same()) { + return "RVA"; + } + if (std::is_same()) { + return "RVA64"; + } + NOTREACHED(); + return ""; + } +}; + +template +class MinidumpContextWriter : public ::testing::Test {}; + +using RVATypes = ::testing::Types; +TYPED_TEST_SUITE(MinidumpContextWriter, RVATypes, TestTypeNames); + +TYPED_TEST(MinidumpContextWriter, MinidumpContextX86Writer) { StringFile string_file; { @@ -50,7 +75,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) { // context. SCOPED_TRACE("zero"); - EmptyContextTest( + EmptyContextTest( ExpectMinidumpContextX86); } @@ -67,14 +92,15 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) { ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextX86)); const MinidumpContextX86* observed = - MinidumpWritableAtRVA(string_file.string(), 0); + MinidumpWritableAtRVA(string_file.string(), + TypeParam(0)); ASSERT_TRUE(observed); ExpectMinidumpContextX86(kSeed, observed, false); } } -TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { +TYPED_TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { { // Make sure that a heap-allocated context writer has the proper alignment, // because it may be nonstandard. @@ -91,8 +117,9 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { // context. SCOPED_TRACE("zero"); - EmptyContextTest( - ExpectMinidumpContextAMD64); + EmptyContextTest(ExpectMinidumpContextAMD64); } { @@ -108,52 +135,53 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { ASSERT_EQ(string_file.string().size(), sizeof(MinidumpContextAMD64)); const MinidumpContextAMD64* observed = - MinidumpWritableAtRVA(string_file.string(), 0); + MinidumpWritableAtRVA(string_file.string(), + TypeParam(0)); ASSERT_TRUE(observed); ExpectMinidumpContextAMD64(kSeed, observed, false); } } -template +template void FromSnapshotTest(const CPUContext& snapshot_context, void (*expect_context)(uint32_t, const Context*, bool), uint32_t seed) { - std::unique_ptr context_writer = - MinidumpContextWriter::CreateFromSnapshot(&snapshot_context); + std::unique_ptr<::crashpad::MinidumpContextWriter> context_writer = + ::crashpad::MinidumpContextWriter::CreateFromSnapshot(&snapshot_context); ASSERT_TRUE(context_writer); StringFile string_file; ASSERT_TRUE(context_writer->WriteEverything(&string_file)); const Context* observed = - MinidumpWritableAtRVA(string_file.string(), 0); + MinidumpWritableAtRVA(string_file.string(), RVAType(0)); ASSERT_TRUE(observed); expect_context(seed, observed, true); } -TEST(MinidumpContextWriter, X86_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, X86_FromSnapshot) { constexpr uint32_t kSeed = 32; CPUContextX86 context_x86; CPUContext context; context.x86 = &context_x86; InitializeCPUContextX86(&context, kSeed); - FromSnapshotTest( + FromSnapshotTest( context, ExpectMinidumpContextX86, kSeed); } -TEST(MinidumpContextWriter, AMD64_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, AMD64_FromSnapshot) { constexpr uint32_t kSeed = 64; CPUContextX86_64 context_x86_64; CPUContext context; context.x86_64 = &context_x86_64; InitializeCPUContextX86_64(&context, kSeed); - FromSnapshotTest( + FromSnapshotTest( context, ExpectMinidumpContextAMD64, kSeed); } -TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) { +TYPED_TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) { constexpr uint32_t kSeed = 77; CPUContextX86_64 context_x86_64; CPUContext context; @@ -163,78 +191,81 @@ TEST(MinidumpContextWriter, AMD64_CetFromSnapshot) { context_x86_64.xstate.cet_u.cetmsr = 1; context_x86_64.xstate.cet_u.ssp = kSeed * kSeed; // We cannot use FromSnapshotTest as we write more than the fixed context. - std::unique_ptr context_writer = - MinidumpContextWriter::CreateFromSnapshot(&context); + std::unique_ptr<::crashpad::MinidumpContextWriter> context_writer = + ::crashpad::MinidumpContextWriter::CreateFromSnapshot(&context); ASSERT_TRUE(context_writer); StringFile string_file; ASSERT_TRUE(context_writer->WriteEverything(&string_file)); const MinidumpContextAMD64* observed = - MinidumpWritableAtRVA(string_file.string(), 0); + MinidumpWritableAtRVA(string_file.string(), + TypeParam(0)); ASSERT_TRUE(observed); ExpectMinidumpContextAMD64(kSeed, observed, true); } -TEST(MinidumpContextWriter, ARM_Zeros) { - EmptyContextTest( +TYPED_TEST(MinidumpContextWriter, ARM_Zeros) { + EmptyContextTest( ExpectMinidumpContextARM); } -TEST(MinidumpContextWRiter, ARM64_Zeros) { - EmptyContextTest( +TYPED_TEST(MinidumpContextWriter, ARM64_Zeros) { + EmptyContextTest( ExpectMinidumpContextARM64); } -TEST(MinidumpContextWriter, ARM_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, ARM_FromSnapshot) { constexpr uint32_t kSeed = 32; CPUContextARM context_arm; CPUContext context; context.arm = &context_arm; InitializeCPUContextARM(&context, kSeed); - FromSnapshotTest( + FromSnapshotTest( context, ExpectMinidumpContextARM, kSeed); } -TEST(MinidumpContextWriter, ARM64_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, ARM64_FromSnapshot) { constexpr uint32_t kSeed = 64; CPUContextARM64 context_arm64; CPUContext context; context.arm64 = &context_arm64; InitializeCPUContextARM64(&context, kSeed); - FromSnapshotTest( + FromSnapshotTest( context, ExpectMinidumpContextARM64, kSeed); } -TEST(MinidumpContextWriter, MIPS_Zeros) { - EmptyContextTest( +TYPED_TEST(MinidumpContextWriter, MIPS_Zeros) { + EmptyContextTest( ExpectMinidumpContextMIPS); } -TEST(MinidumpContextWriter, MIPS64_Zeros) { - EmptyContextTest( - ExpectMinidumpContextMIPS64); +TYPED_TEST(MinidumpContextWriter, MIPS64_Zeros) { + EmptyContextTest(ExpectMinidumpContextMIPS64); } -TEST(MinidumpContextWriter, MIPS_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, MIPS_FromSnapshot) { constexpr uint32_t kSeed = 32; CPUContextMIPS context_mips; CPUContext context; context.mipsel = &context_mips; InitializeCPUContextMIPS(&context, kSeed); - FromSnapshotTest( + FromSnapshotTest( context, ExpectMinidumpContextMIPS, kSeed); } -TEST(MinidumpContextWriter, MIPS64_FromSnapshot) { +TYPED_TEST(MinidumpContextWriter, MIPS64_FromSnapshot) { constexpr uint32_t kSeed = 64; CPUContextMIPS64 context_mips; CPUContext context; context.mips64 = &context_mips; InitializeCPUContextMIPS64(&context, kSeed); - FromSnapshotTest( - context, ExpectMinidumpContextMIPS64, kSeed); + FromSnapshotTest(context, ExpectMinidumpContextMIPS64, kSeed); } } // namespace diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index f0cdb827f9..00b87653d9 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -16,8 +16,10 @@ #include #include +#include #include "base/format_macros.h" +#include "base/notreached.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" @@ -30,7 +32,28 @@ namespace crashpad { namespace test { namespace { -TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { +class TestTypeNames { + public: + template + static std::string GetName(int) { + if (std::is_same()) { + return "RVA"; + } + if (std::is_same()) { + return "RVA64"; + } + NOTREACHED(); + return ""; + } +}; + +template +class MinidumpStringWriter : public ::testing::Test {}; + +using RVATypes = ::testing::Types; +TYPED_TEST_SUITE(MinidumpStringWriter, RVATypes, TestTypeNames); + +TYPED_TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { StringFile string_file; { @@ -41,9 +64,9 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { ASSERT_EQ(string_file.string().size(), 6u); const MINIDUMP_STRING* minidump_string = - MinidumpStringAtRVA(string_file.string(), 0); + MinidumpStringAtRVA(string_file.string(), TypeParam(0)); EXPECT_TRUE(minidump_string); - EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), 0), + EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0)), std::u16string()); } @@ -90,16 +113,16 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { ASSERT_EQ(string_file.string().size(), sizeof(*tmp) + expected_utf16_bytes); const MINIDUMP_STRING* minidump_string = - MinidumpStringAtRVA(string_file.string(), 0); + MinidumpStringAtRVA(string_file.string(), TypeParam(0)); EXPECT_TRUE(minidump_string); std::u16string expect_string = std::u16string( kTestData[index].output_string, kTestData[index].output_length); - EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), 0), + EXPECT_EQ(MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0)), expect_string); } } -TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { +TYPED_TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { StringFile string_file; static constexpr const char* kTestData[] = { @@ -125,20 +148,20 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { // data written, and make sure that at least one U+FFFD replacement // character was written. const MINIDUMP_STRING* minidump_string = - MinidumpStringAtRVA(string_file.string(), 0); + MinidumpStringAtRVA(string_file.string(), TypeParam(0)); EXPECT_TRUE(minidump_string); [[maybe_unused]] MINIDUMP_STRING* tmp; EXPECT_EQ( minidump_string->Length, string_file.string().size() - sizeof(*tmp) - sizeof(tmp->Buffer[0])); std::u16string output_string = - MinidumpStringAtRVAAsString(string_file.string(), 0); + MinidumpStringAtRVAAsString(string_file.string(), TypeParam(0)); EXPECT_FALSE(output_string.empty()); EXPECT_NE(output_string.find(0xfffd), std::u16string::npos); } } -TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { +TYPED_TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { StringFile string_file; { @@ -149,10 +172,11 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { ASSERT_EQ(string_file.string().size(), 5u); const MinidumpUTF8String* minidump_string = - MinidumpUTF8StringAtRVA(string_file.string(), 0); + MinidumpUTF8StringAtRVA(string_file.string(), TypeParam(0)); EXPECT_TRUE(minidump_string); - EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(), 0), - std::string()); + EXPECT_EQ( + MinidumpUTF8StringAtRVAAsString(string_file.string(), TypeParam(0)), + std::string()); } static constexpr struct { @@ -188,10 +212,11 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { sizeof(MinidumpUTF8String) + expected_utf8_bytes_with_nul); const MinidumpUTF8String* minidump_string = - MinidumpUTF8StringAtRVA(string_file.string(), 0); + MinidumpUTF8StringAtRVA(string_file.string(), TypeParam(0)); EXPECT_TRUE(minidump_string); - EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(), 0), - test_string); + EXPECT_EQ( + MinidumpUTF8StringAtRVAAsString(string_file.string(), TypeParam(0)), + test_string); } } @@ -245,11 +270,11 @@ void MinidumpStringListTest() { } } -TEST(MinidumpStringWriter, MinidumpUTF16StringList) { +TYPED_TEST(MinidumpStringWriter, MinidumpUTF16StringList) { MinidumpStringListTest(); } -TEST(MinidumpStringWriter, MinidumpUTF8StringList) { +TYPED_TEST(MinidumpStringWriter, MinidumpUTF8StringList) { MinidumpStringListTest(); } diff --git a/minidump/test/minidump_string_writer_test_util.cc b/minidump/test/minidump_string_writer_test_util.cc index a8eb5aa46a..0001bda0a3 100644 --- a/minidump/test/minidump_string_writer_test_util.cc +++ b/minidump/test/minidump_string_writer_test_util.cc @@ -25,8 +25,11 @@ namespace test { namespace { -template -const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) { +template < + typename T, + typename RVAType = RVA, + typename MinidumpLocationDescriptorType = MINIDUMP_LOCATION_DESCRIPTOR> +const T* TMinidumpStringAtRVA(const std::string& file_contents, RVAType rva) { const T* string_base = MinidumpWritableAtRVA(file_contents, rva); if (!string_base) { return nullptr; @@ -41,7 +44,7 @@ const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) { } // |Length| does not include space for the required NUL terminator. - MINIDUMP_LOCATION_DESCRIPTOR location; + MinidumpLocationDescriptorType location; location.DataSize = sizeof(*string_base) + string_base->Length + kCodeUnitSize; location.Rva = rva; @@ -62,11 +65,16 @@ const T* TMinidumpStringAtRVA(const std::string& file_contents, RVA rva) { return string; } -template +template StringType TMinidumpStringAtRVAAsString(const std::string& file_contents, - RVA rva) { + RVAType rva) { const MinidumpStringType* minidump_string = - TMinidumpStringAtRVA(file_contents, rva); + TMinidumpStringAtRVA(file_contents, rva); if (!minidump_string) { return StringType(); } @@ -82,24 +90,69 @@ StringType TMinidumpStringAtRVAAsString(const std::string& file_contents, const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents, RVA rva) { - return TMinidumpStringAtRVA(file_contents, rva); + return TMinidumpStringAtRVA(file_contents, rva); +} + +const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents, + RVA64 rva) { + return TMinidumpStringAtRVA(file_contents, + rva); } const MinidumpUTF8String* MinidumpUTF8StringAtRVA( const std::string& file_contents, RVA rva) { - return TMinidumpStringAtRVA(file_contents, rva); + return TMinidumpStringAtRVA(file_contents, rva); +} + +const MinidumpUTF8String* MinidumpUTF8StringAtRVA( + const std::string& file_contents, + RVA64 rva) { + return TMinidumpStringAtRVA(file_contents, + rva); } std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents, RVA rva) { - return TMinidumpStringAtRVAAsString( + return TMinidumpStringAtRVAAsString( + file_contents, rva); +} + +std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents, + RVA64 rva) { + return TMinidumpStringAtRVAAsString( file_contents, rva); } std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents, RVA rva) { - return TMinidumpStringAtRVAAsString( + return TMinidumpStringAtRVAAsString( + file_contents, rva); +} + +std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents, + RVA64 rva) { + return TMinidumpStringAtRVAAsString( file_contents, rva); } diff --git a/minidump/test/minidump_string_writer_test_util.h b/minidump/test/minidump_string_writer_test_util.h index c92027a70d..f2c0f04039 100644 --- a/minidump/test/minidump_string_writer_test_util.h +++ b/minidump/test/minidump_string_writer_test_util.h @@ -20,6 +20,11 @@ #include +#include "minidump/minidump_extensions.h" +#include "minidump/test/minidump_writable_test_util.h" + +#include "gtest/gtest.h" + namespace crashpad { struct MinidumpUTF8String; @@ -44,6 +49,10 @@ namespace test { const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents, RVA rva); +//! \brief 64-bit specialization of MinidumpStringAtRVA. +const MINIDUMP_STRING* MinidumpStringAtRVA(const std::string& file_contents, + RVA64 rva); + //! \brief Returns a MinidumpUTF8String located within a minidump file’s //! contents. //! @@ -64,6 +73,11 @@ const MinidumpUTF8String* MinidumpUTF8StringAtRVA( const std::string& file_contents, RVA rva); +//! \brief 64-bit specialization of MinidumpUTF8StringAtRVA. +const MinidumpUTF8String* MinidumpUTF8StringAtRVA( + const std::string& file_contents, + RVA64 rva); + //! \brief Returns the contents of a MINIDUMP_STRING as a `std::u16string`. //! //! This function uses MinidumpStringAtRVA() to obtain a MINIDUMP_STRING, and @@ -80,6 +94,10 @@ const MinidumpUTF8String* MinidumpUTF8StringAtRVA( std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents, RVA rva); +//! \brief 64-bit specialization of MinidumpStringAtRVAAsString. +std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents, + RVA64 rva); + //! \brief Returns the contents of a MinidumpUTF8String as a `std::string`. //! //! This function uses MinidumpUTF8StringAtRVA() to obtain a MinidumpUTF8String, @@ -96,6 +114,10 @@ std::u16string MinidumpStringAtRVAAsString(const std::string& file_contents, std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents, RVA rva); +//! \brief 64-bit specialization of MinidumpUTF8StringAtRVAAsString. +std::string MinidumpUTF8StringAtRVAAsString(const std::string& file_contents, + RVA64 rva); + } // namespace test } // namespace crashpad diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index 2ae6a9b14c..effc04c595 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "util/file/file_writer.h" #include "util/misc/implicit_cast.h" +#include "util/numeric/in_range_cast.h" namespace crashpad { namespace test { @@ -39,25 +40,26 @@ namespace { //! //! Do not call this function. Use the typed version, MinidumpWritableAtRVA<>(), //! or another type-specific function. +template const void* MinidumpWritableAtRVAInternal(const std::string& file_contents, - RVA rva) { - if (rva >= file_contents.size()) { - EXPECT_LT(rva, file_contents.size()); + RVAType rva) { + const auto rva_offset = crashpad::InRangeCast(rva, file_contents.size()); + if (rva_offset >= file_contents.size()) { + EXPECT_LT(rva_offset, file_contents.size()); return nullptr; } - return &file_contents[rva]; + return &file_contents[rva_offset]; } -} // namespace - -const void* MinidumpWritableAtLocationDescriptorInternal( +template +const void* TMinidumpWritableAtLocationDescriptorInternal( const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location, + const MinidumpLocationDescriptorType& location, size_t expected_size, bool allow_oversized_data) { if (location.DataSize == 0) { - EXPECT_EQ(location.Rva, 0u); + EXPECT_EQ(location.Rva, RVAType(0)); return nullptr; } @@ -71,17 +73,42 @@ const void* MinidumpWritableAtLocationDescriptorInternal( return nullptr; } - RVA end = location.Rva + location.DataSize; + RVAType end = location.Rva + location.DataSize; if (end > file_contents.size()) { EXPECT_LE(end, file_contents.size()); return nullptr; } - const void* rv = MinidumpWritableAtRVAInternal(file_contents, location.Rva); + const void* rv = + MinidumpWritableAtRVAInternal(file_contents, location.Rva); return rv; } +} // namespace + +const void* MinidumpWritableAtLocationDescriptorInternal( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location, + size_t expected_size, + bool allow_oversized_data) { + return TMinidumpWritableAtLocationDescriptorInternal< + RVA, + MINIDUMP_LOCATION_DESCRIPTOR>( + file_contents, location, expected_size, allow_oversized_data); +} + +const void* MinidumpWritableAtLocationDescriptorInternal( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR64& location, + size_t expected_size, + bool allow_oversized_data) { + return TMinidumpWritableAtLocationDescriptorInternal< + RVA64, + MINIDUMP_LOCATION_DESCRIPTOR64>( + file_contents, location, expected_size, allow_oversized_data); +} + template <> const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor( const std::string& file_contents, diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h index 9ebb9d0266..7560558ea8 100644 --- a/minidump/test/minidump_writable_test_util.h +++ b/minidump/test/minidump_writable_test_util.h @@ -59,6 +59,17 @@ const void* MinidumpWritableAtLocationDescriptorInternal( size_t expected_size, bool allow_oversized_data); +//! \brief 64-bit specialization of +//! MinidumpWritableAtLocationDescriptorInternal. +//! +//! Do not call this function. Use the typed version, +//! MinidumpWritableAtLocationDescriptor<>(), or another type-specific function. +const void* MinidumpWritableAtLocationDescriptorInternal( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR64& location, + size_t expected_size, + bool allow_oversized_data); + //! \brief A traits class defining whether a minidump object type is required to //! appear only as a fixed-size object or if it is variable-sized. //! @@ -134,6 +145,22 @@ const T* TMinidumpWritableAtLocationDescriptor( MinidumpWritableTraits::kAllowOversizedData)); } +//! \brief 64-bit specialization of TMinidumpWritableAtLocationDescriptor. +//! +//! Do not call this function directly. Use +//! MinidumpWritableAtLocationDescriptor<>() instead. +template +const T* TMinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR64& location) { + return reinterpret_cast( + MinidumpWritableAtLocationDescriptorInternal( + file_contents, + location, + sizeof(T), + MinidumpWritableTraits::kAllowOversizedData)); +} + //! \brief Returns a typed minidump object located within a minidump file’s //! contents, where the offset and size of the object are known. //! @@ -168,6 +195,14 @@ const T* MinidumpWritableAtLocationDescriptor( return TMinidumpWritableAtLocationDescriptor(file_contents, location); } +//! \brief 64-bit specialization of MinidumpWritableAtLocationDescriptor. +template +const T* MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR64& location) { + return TMinidumpWritableAtLocationDescriptor(file_contents, location); +} + template <> const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor( const std::string& file_contents, @@ -270,6 +305,15 @@ const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA rva) { return MinidumpWritableAtLocationDescriptor(file_contents, location); } +//! \brief 64-bit specialization of MinidumpWritableAtRVA. +template +const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA64 rva) { + MINIDUMP_LOCATION_DESCRIPTOR64 location; + location.DataSize = sizeof(T); + location.Rva = rva; + return MinidumpWritableAtLocationDescriptor(file_contents, location); +} + //! \brief An internal::MinidumpWritable that carries a `uint32_t` for testing. class TestUInt32MinidumpWritable final : public internal::MinidumpWritable { public: diff --git a/snapshot/minidump/minidump_string_reader.cc b/snapshot/minidump/minidump_string_reader.cc index 0e9527c200..0ef93308a5 100644 --- a/snapshot/minidump/minidump_string_reader.cc +++ b/snapshot/minidump/minidump_string_reader.cc @@ -24,10 +24,10 @@ namespace internal { namespace { -template +template bool ReadMinidumpString(FileReaderInterface* file_reader, - RVA rva, - StringType* string) { + RVAType rva, + StringType* string) { if (rva == 0) { string->clear(); return true; @@ -59,12 +59,24 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, return ReadMinidumpString(file_reader, rva, string); } +bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, + RVA64 rva, + std::string* string) { + return ReadMinidumpString(file_reader, rva, string); +} + bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, RVA rva, std::u16string* string) { return ReadMinidumpString(file_reader, rva, string); } +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA64 rva, + std::u16string* string) { + return ReadMinidumpString(file_reader, rva, string); +} + bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, RVA rva, std::string* string) { @@ -79,5 +91,19 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, return true; } +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA64 rva, + std::string* string) { + std::u16string string_raw; + + if (!ReadMinidumpString(file_reader, rva, &string_raw)) { + return false; + } + + base::UTF16ToUTF8(string_raw.data(), string_raw.size(), string); + + return true; +} + } // namespace internal } // namespace crashpad diff --git a/snapshot/minidump/minidump_string_reader.h b/snapshot/minidump/minidump_string_reader.h index 370fa8c194..3618aa34f3 100644 --- a/snapshot/minidump/minidump_string_reader.h +++ b/snapshot/minidump/minidump_string_reader.h @@ -20,6 +20,8 @@ #include +#include "base/strings/utf_string_conversions.h" +#include "minidump/minidump_extensions.h" #include "util/file/file_reader.h" namespace crashpad { @@ -34,6 +36,11 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, RVA rva, std::string* string); +//! \brief 64-bit specialization of ReadMinidumpUTF8String. +bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, + RVA64 rva, + std::string* string); + //! \brief Reads a MinidumpUTF16String from a minidump file at offset \a rva in //! \a file_reader, and returns it in \a string. //! @@ -43,6 +50,11 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, RVA rva, std::u16string* string); +//! \brief 64-bit specialization of ReadMinidumpUTF16String. +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA64 rva, + std::u16string* string); + //! \brief Reads a MinidumpUTF16String from a minidump file at offset \a rva in //! \a file_reader, and returns it in \a string. //! @@ -52,6 +64,11 @@ bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, RVA rva, std::string* string); +//! \brief 64-bit specialization of ReadMinidumpUTF16String. +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA64 rva, + std::string* string); + } // namespace internal } // namespace crashpad From 6d0d1a4be63b8de0e7aab0d7c11ad9da930913b4 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Mon, 6 Jun 2022 09:29:39 -0600 Subject: [PATCH 179/478] [minidump] Add support for THREAD_NAME_LIST stream The minidump stream type MINIDUMP_THREAD_NAME_LIST represents thread names as a list in the form [(thread_id, thread name), ...]. This introduces a new MinidumpThreadNameListWriter class which allows OS-specific snapshot writers to write thread names using this new stream type. Bug: crashpad:327 Change-Id: Ief45df5dbbf44c0e1254786bfbe6720112ceef38 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3671775 Reviewed-by: Joshua Peraza Commit-Queue: Ben Hamilton --- compat/non_win/dbghelp.h | 24 ++ minidump/BUILD.gn | 3 + minidump/minidump_extensions.h | 5 + minidump/minidump_thread_name_list_writer.cc | 160 +++++++++++ minidump/minidump_thread_name_list_writer.h | 110 ++++++++ .../minidump_thread_name_list_writer_test.cc | 251 ++++++++++++++++++ minidump/test/minidump_writable_test_util.cc | 17 ++ minidump/test/minidump_writable_test_util.h | 10 +- 8 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 minidump/minidump_thread_name_list_writer.cc create mode 100644 minidump/minidump_thread_name_list_writer.h create mode 100644 minidump/minidump_thread_name_list_writer_test.cc diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 0618b91533..55fd47b98c 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -195,6 +195,9 @@ enum MINIDUMP_STREAM_TYPE { //! \brief The stream type for MINIDUMP_MEMORY_INFO_LIST. MemoryInfoListStream = 16, + //! \brief The stream type for MINIDUMP_THREAD_NAME_LIST. + ThreadNamesStream = 24, + //! \brief Values greater than this value will not be used by the system //! and can be used for custom user data streams. LastReservedStream = 0xffff, @@ -1099,6 +1102,27 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MEMORY_INFO_LIST { uint64_t NumberOfEntries; }; +//! \brief Contains the name of the thread with the given thread ID. +struct __attribute__((packed, aligned(4))) MINIDUMP_THREAD_NAME { + //! \brief The identifier of the thread. + uint32_t ThreadId; + + //! \brief RVA64 of a MINIDUMP_STRING containing the name of the thread. + RVA64 RvaOfThreadName; +}; + +//! \brief Variable-sized struct which contains a list of MINIDUMP_THREAD_NAME +//! structs. +struct __attribute__((packed, aligned(4))) MINIDUMP_THREAD_NAME_LIST { + //! \brief The number of MINIDUMP_THREAD_NAME structs following this field. + uint32_t NumberOfThreadNames; + + //! \brief A variably-sized array containing zero or more + //! MINIDUMP_THREAD_NAME structs. The length of the array is indicated by + //! the NumberOfThreadNames field in this struct. + struct MINIDUMP_THREAD_NAME ThreadNames[0]; +}; + //! \brief Minidump file type values for MINIDUMP_HEADER::Flags. These bits //! describe the types of data carried within a minidump file. enum MINIDUMP_TYPE { diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index 515ec0f377..a300897f80 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -52,6 +52,8 @@ crashpad_static_library("minidump") { "minidump_system_info_writer.h", "minidump_thread_id_map.cc", "minidump_thread_id_map.h", + "minidump_thread_name_list_writer.cc", + "minidump_thread_name_list_writer.h", "minidump_thread_writer.cc", "minidump_thread_writer.h", "minidump_unloaded_module_writer.cc", @@ -166,6 +168,7 @@ source_set("minidump_test") { "minidump_string_writer_test.cc", "minidump_system_info_writer_test.cc", "minidump_thread_id_map_test.cc", + "minidump_thread_name_list_writer_test.cc", "minidump_thread_writer_test.cc", "minidump_unloaded_module_writer_test.cc", "minidump_user_stream_writer_test.cc", diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 97276d529a..35e6f40eb3 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -93,6 +93,11 @@ enum MinidumpStreamType : uint32_t { //! \sa MemoryInfoListStream kMinidumpStreamTypeMemoryInfoList = MemoryInfoListStream, + //! \brief The stream type for MINIDUMP_THREAD_NAME_LIST. + //! + //! \sa ThreadNamesStream + kMinidumpStreamTypeThreadNameList = ThreadNamesStream, + //! \brief The last reserved minidump stream. //! //! \sa MemoryInfoListStream diff --git a/minidump/minidump_thread_name_list_writer.cc b/minidump/minidump_thread_name_list_writer.cc new file mode 100644 index 0000000000..91a02d8883 --- /dev/null +++ b/minidump/minidump_thread_name_list_writer.cc @@ -0,0 +1,160 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "minidump/minidump_thread_name_list_writer.h" + +#include + +#include "base/logging.h" +#include "util/file/file_writer.h" +#include "util/numeric/safe_assignment.h" + +namespace crashpad { + +MinidumpThreadNameWriter::MinidumpThreadNameWriter() + : MinidumpWritable(), thread_name_(), name_() {} + +MinidumpThreadNameWriter::~MinidumpThreadNameWriter() {} + +const MINIDUMP_THREAD_NAME* MinidumpThreadNameWriter::MinidumpThreadName() + const { + DCHECK_EQ(state(), kStateWritable); + + return &thread_name_; +} + +void MinidumpThreadNameWriter::SetThreadName(const std::string& name) { + DCHECK_EQ(state(), kStateMutable); + + if (!name_) { + name_.reset(new internal::MinidumpUTF16StringWriter()); + } + name_->SetUTF8(name); +} + +bool MinidumpThreadNameWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + if (!MinidumpWritable::Freeze()) { + return false; + } + + name_->RegisterRVA(&thread_name_.RvaOfThreadName); + + return true; +} + +size_t MinidumpThreadNameWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + + // This object doesn’t directly write anything itself. Its + // MINIDUMP_THREAD_NAME is written by its parent as part of a + // MINIDUMP_THREAD_NAME_LIST, and its children are responsible for writing + // themselves. + return 0; +} + +std::vector MinidumpThreadNameWriter::Children() { + DCHECK_GE(state(), kStateFrozen); + DCHECK(name_); + + std::vector children; + children.emplace_back(name_.get()); + + return children; +} + +bool MinidumpThreadNameWriter::WriteObject(FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + + // This object doesn’t directly write anything itself. Its + // MINIDUMP_THREAD_NAME is written by its parent as part of a + // MINIDUMP_THREAD_NAME_LIST, and its children are responsible for writing + // themselves. + return true; +} + +MinidumpThreadNameListWriter::MinidumpThreadNameListWriter() + : MinidumpStreamWriter(), thread_names_() {} + +MinidumpThreadNameListWriter::~MinidumpThreadNameListWriter() {} + +void MinidumpThreadNameListWriter::AddThreadName( + std::unique_ptr thread_name) { + DCHECK_EQ(state(), kStateMutable); + + thread_names_.emplace_back(std::move(thread_name)); +} + +bool MinidumpThreadNameListWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + if (!MinidumpStreamWriter::Freeze()) { + return false; + } + + size_t thread_name_count = thread_names_.size(); + if (!AssignIfInRange(&thread_name_list_.NumberOfThreadNames, + thread_name_count)) { + LOG(ERROR) << "thread_name_count " << thread_name_count << " out of range"; + return false; + } + + return true; +} + +size_t MinidumpThreadNameListWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + + return sizeof(thread_name_list_) + + thread_names_.size() * sizeof(MINIDUMP_THREAD_NAME); +} + +std::vector +MinidumpThreadNameListWriter::Children() { + DCHECK_GE(state(), kStateFrozen); + + std::vector children; + children.reserve(thread_names_.size()); + for (const auto& thread_name : thread_names_) { + children.emplace_back(thread_name.get()); + } + + return children; +} + +bool MinidumpThreadNameListWriter::WriteObject( + FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + + WritableIoVec iov; + iov.iov_base = &thread_name_list_; + iov.iov_len = sizeof(thread_name_list_); + std::vector iovecs(1, iov); + iovecs.reserve(thread_names_.size() + 1); + + for (const auto& thread_name : thread_names_) { + iov.iov_base = thread_name->MinidumpThreadName(); + iov.iov_len = sizeof(MINIDUMP_THREAD_NAME); + iovecs.emplace_back(iov); + } + + return file_writer->WriteIoVec(&iovecs); +} + +MinidumpStreamType MinidumpThreadNameListWriter::StreamType() const { + return kMinidumpStreamTypeThreadNameList; +} + +} // namespace crashpad diff --git a/minidump/minidump_thread_name_list_writer.h b/minidump/minidump_thread_name_list_writer.h new file mode 100644 index 0000000000..9cfe2d087d --- /dev/null +++ b/minidump/minidump_thread_name_list_writer.h @@ -0,0 +1,110 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_THREAD_NAME_LIST_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_THREAD_NAME_LIST_WRITER_H_ + +#include +#include +#include +#include + +#include +#include + +#include "minidump/minidump_stream_writer.h" +#include "minidump/minidump_string_writer.h" +#include "minidump/minidump_writable.h" + +namespace crashpad { + +//! \brief The writer for a MINIDUMP_THREAD_NAME object in a minidump file. +//! +//! Because MINIDUMP_THREAD_NAME objects only appear as elements of +//! MINIDUMP_THREAD_NAME_LIST objects, this class does not write any data on its +//! own. It makes its MINIDUMP_THREAD_NAME data available to its +//! MinidumpThreadNameListWriter parent, which writes it as part of a +//! MINIDUMP_THREAD_NAME_LIST. +class MinidumpThreadNameWriter final : public internal::MinidumpWritable { + public: + MinidumpThreadNameWriter(); + + MinidumpThreadNameWriter(const MinidumpThreadNameWriter&) = delete; + MinidumpThreadNameWriter& operator=(const MinidumpThreadNameWriter&) = delete; + + ~MinidumpThreadNameWriter() override; + + //! \brief Returns a MINIDUMP_THREAD_NAME referencing this object’s data. + //! + //! This method is expected to be called by a MinidumpThreadNameListWriter in + //! order to obtain a MINIDUMP_THREAD_NAME to include in its list. + //! + //! \note Valid in #kStateWritable. + const MINIDUMP_THREAD_NAME* MinidumpThreadName() const; + + //! \brief Sets MINIDUMP_THREAD_NAME::ThreadId. + void SetThreadId(uint32_t thread_id) { thread_name_.ThreadId = thread_id; } + + //! \brief Sets MINIDUMP_THREAD_NAME::RvaOfThreadName. + void SetThreadName(const std::string& thread_name); + + private: + // MinidumpWritable: + bool Freeze() override; + size_t SizeOfObject() override; + std::vector Children() override; + bool WriteObject(FileWriterInterface* file_writer) override; + + MINIDUMP_THREAD_NAME thread_name_; + std::unique_ptr name_; +}; + +//! \brief The writer for a MINIDUMP_THREAD_NAME_LIST stream in a minidump file, +//! containing a list of MINIDUMP_THREAD_NAME objects. +class MinidumpThreadNameListWriter final + : public internal::MinidumpStreamWriter { + public: + MinidumpThreadNameListWriter(); + + MinidumpThreadNameListWriter(const MinidumpThreadNameListWriter&) = delete; + MinidumpThreadNameListWriter& operator=(const MinidumpThreadNameListWriter&) = + delete; + + ~MinidumpThreadNameListWriter() override; + + //! \brief Adds a MinidumpThreadNameWriter to the MINIDUMP_THREAD_LIST. + //! + //! This object takes ownership of \a thread_name and becomes its parent in + //! the overall tree of internal::MinidumpWritable objects. + //! + //! \note Valid in #kStateMutable. + void AddThreadName(std::unique_ptr thread_name); + + private: + // MinidumpWritable: + bool Freeze() override; + size_t SizeOfObject() override; + std::vector Children() override; + bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpStreamWriter: + MinidumpStreamType StreamType() const override; + + std::vector> thread_names_; + MINIDUMP_THREAD_NAME_LIST thread_name_list_; +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_THREAD_NAME_LIST_WRITER_H_ diff --git a/minidump/minidump_thread_name_list_writer_test.cc b/minidump/minidump_thread_name_list_writer_test.cc new file mode 100644 index 0000000000..b61b1bb4da --- /dev/null +++ b/minidump/minidump_thread_name_list_writer_test.cc @@ -0,0 +1,251 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "minidump/minidump_thread_name_list_writer.h" + +#include +#include +#include + +#include "base/compiler_specific.h" +#include "base/format_macros.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "gtest/gtest.h" +#include "minidump/minidump_file_writer.h" +#include "minidump/test/minidump_file_writer_test_util.h" +#include "minidump/test/minidump_string_writer_test_util.h" +#include "minidump/test/minidump_writable_test_util.h" +#include "test/gtest_death.h" +#include "util/file/string_file.h" + +namespace crashpad { +namespace test { +namespace { + +// This returns the MINIDUMP_THREAD_NAME_LIST stream in |thread_name_list|. +void GetThreadNameListStream( + const std::string& file_contents, + const MINIDUMP_THREAD_NAME_LIST** thread_name_list) { + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + const uint32_t kExpectedStreams = 1; + const size_t kThreadNameListStreamOffset = + kDirectoryOffset + kExpectedStreams * sizeof(MINIDUMP_DIRECTORY); + const size_t kThreadNameListOffset = + kThreadNameListStreamOffset + sizeof(MINIDUMP_THREAD_NAME_LIST); + + ASSERT_GE(file_contents.size(), kThreadNameListOffset); + + const MINIDUMP_DIRECTORY* directory; + const MINIDUMP_HEADER* header = + MinidumpHeaderAtStart(file_contents, &directory); + ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, kExpectedStreams, 0)); + ASSERT_TRUE(directory); + + ASSERT_EQ(directory[0].StreamType, kMinidumpStreamTypeThreadNameList); + EXPECT_EQ(directory[0].Location.Rva, kThreadNameListStreamOffset); + + *thread_name_list = + MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(thread_name_list); +} + +TEST(MinidumpThreadNameListWriter, EmptyThreadNameList) { + MinidumpFileWriter minidump_file_writer; + auto thread_name_list_writer = + std::make_unique(); + + ASSERT_TRUE( + minidump_file_writer.AddStream(std::move(thread_name_list_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_EQ(string_file.string().size(), + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + + sizeof(MINIDUMP_THREAD_NAME_LIST)); + + const MINIDUMP_THREAD_NAME_LIST* thread_name_list = nullptr; + ASSERT_NO_FATAL_FAILURE( + GetThreadNameListStream(string_file.string(), &thread_name_list)); + + EXPECT_EQ(thread_name_list->NumberOfThreadNames, 0u); +} + +// The MINIDUMP_THREAD_NAMEs |expected| and |observed| are compared against +// each other using Google Test assertions. +void ExpectThreadName(const MINIDUMP_THREAD_NAME* expected, + const MINIDUMP_THREAD_NAME* observed, + const std::string& file_contents, + const std::string& expected_thread_name) { + EXPECT_EQ(observed->ThreadId, expected->ThreadId); + EXPECT_NE(observed->RvaOfThreadName, 0u); + const std::string observed_thread_name = base::UTF16ToUTF8( + MinidumpStringAtRVAAsString(file_contents, observed->RvaOfThreadName)); + EXPECT_EQ(observed_thread_name, expected_thread_name); +} + +TEST(MinidumpThreadNameListWriter, OneThread) { + MinidumpFileWriter minidump_file_writer; + auto thread_list_writer = std::make_unique(); + + constexpr uint32_t kThreadID = 0x11111111; + const std::string kThreadName = "ariadne"; + + auto thread_name_list_writer = + std::make_unique(); + auto thread_name_writer = std::make_unique(); + thread_name_writer->SetThreadId(kThreadID); + thread_name_writer->SetThreadName(kThreadName); + thread_name_list_writer->AddThreadName(std::move(thread_name_writer)); + + ASSERT_TRUE( + minidump_file_writer.AddStream(std::move(thread_name_list_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_GT(string_file.string().size(), + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + + sizeof(MINIDUMP_THREAD_NAME_LIST) + + 1 * sizeof(MINIDUMP_THREAD_NAME)); + + const MINIDUMP_THREAD_NAME_LIST* thread_name_list = nullptr; + ASSERT_NO_FATAL_FAILURE( + GetThreadNameListStream(string_file.string(), &thread_name_list)); + + EXPECT_EQ(thread_name_list->NumberOfThreadNames, 1u); + + MINIDUMP_THREAD_NAME expected = {}; + expected.ThreadId = kThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[0], + string_file.string(), + kThreadName)); +} + +TEST(MinidumpThreadNameListWriter, TwoThreads_DifferentNames) { + MinidumpFileWriter minidump_file_writer; + auto thread_list_writer = std::make_unique(); + + constexpr uint32_t kFirstThreadID = 0x11111111; + const std::string kFirstThreadName = "ariadne"; + + constexpr uint32_t kSecondThreadID = 0x22222222; + const std::string kSecondThreadName = "theseus"; + + auto thread_name_list_writer = + std::make_unique(); + auto first_thread_name_writer = std::make_unique(); + first_thread_name_writer->SetThreadId(kFirstThreadID); + first_thread_name_writer->SetThreadName(kFirstThreadName); + thread_name_list_writer->AddThreadName(std::move(first_thread_name_writer)); + + auto second_thread_name_writer = std::make_unique(); + second_thread_name_writer->SetThreadId(kSecondThreadID); + second_thread_name_writer->SetThreadName(kSecondThreadName); + thread_name_list_writer->AddThreadName(std::move(second_thread_name_writer)); + + ASSERT_TRUE( + minidump_file_writer.AddStream(std::move(thread_name_list_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_GT(string_file.string().size(), + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + + sizeof(MINIDUMP_THREAD_NAME_LIST) + + 2 * sizeof(MINIDUMP_THREAD_NAME)); + + const MINIDUMP_THREAD_NAME_LIST* thread_name_list = nullptr; + ASSERT_NO_FATAL_FAILURE( + GetThreadNameListStream(string_file.string(), &thread_name_list)); + + EXPECT_EQ(thread_name_list->NumberOfThreadNames, 2u); + + MINIDUMP_THREAD_NAME expected = {}; + expected.ThreadId = kFirstThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[0], + string_file.string(), + kFirstThreadName)); + + expected.ThreadId = kSecondThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[1], + string_file.string(), + kSecondThreadName)); +} + +TEST(MinidumpThreadNameListWriter, TwoThreads_SameNames) { + MinidumpFileWriter minidump_file_writer; + auto thread_list_writer = std::make_unique(); + + constexpr uint32_t kFirstThreadID = 0x11111111; + const std::string kThreadName = "ariadne"; + + constexpr uint32_t kSecondThreadID = 0x22222222; + + auto thread_name_list_writer = + std::make_unique(); + auto first_thread_name_writer = std::make_unique(); + first_thread_name_writer->SetThreadId(kFirstThreadID); + first_thread_name_writer->SetThreadName(kThreadName); + thread_name_list_writer->AddThreadName(std::move(first_thread_name_writer)); + + auto second_thread_name_writer = std::make_unique(); + second_thread_name_writer->SetThreadId(kSecondThreadID); + second_thread_name_writer->SetThreadName(kThreadName); + thread_name_list_writer->AddThreadName(std::move(second_thread_name_writer)); + + ASSERT_TRUE( + minidump_file_writer.AddStream(std::move(thread_name_list_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_GT(string_file.string().size(), + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + + sizeof(MINIDUMP_THREAD_NAME_LIST) + + 2 * sizeof(MINIDUMP_THREAD_NAME)); + + const MINIDUMP_THREAD_NAME_LIST* thread_name_list = nullptr; + ASSERT_NO_FATAL_FAILURE( + GetThreadNameListStream(string_file.string(), &thread_name_list)); + + EXPECT_EQ(thread_name_list->NumberOfThreadNames, 2u); + + MINIDUMP_THREAD_NAME expected = {}; + expected.ThreadId = kFirstThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[0], + string_file.string(), + kThreadName)); + + expected.ThreadId = kSecondThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[1], + string_file.string(), + kThreadName)); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index effc04c595..429588dae6 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -216,6 +216,14 @@ struct MinidumpThreadListTraits { } }; +struct MinidumpThreadNameListTraits { + using ListType = MINIDUMP_THREAD_NAME_LIST; + enum : size_t { kElementSize = sizeof(MINIDUMP_THREAD_NAME) }; + static size_t ElementCount(const ListType* list) { + return list->NumberOfThreadNames; + } +}; + struct MinidumpHandleDataStreamTraits { using ListType = MINIDUMP_HANDLE_DATA_STREAM; enum : size_t { kElementSize = sizeof(MINIDUMP_HANDLE_DESCRIPTOR) }; @@ -309,6 +317,15 @@ MinidumpWritableAtLocationDescriptor( file_contents, location); } +template <> +const MINIDUMP_THREAD_NAME_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpListAtLocationDescriptor( + file_contents, location); +} + template <> const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor( diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h index 7560558ea8..3a11fbf0a2 100644 --- a/minidump/test/minidump_writable_test_util.h +++ b/minidump/test/minidump_writable_test_util.h @@ -101,6 +101,7 @@ MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MEMORY_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MODULE_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_UNLOADED_MODULE_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_THREAD_LIST); +MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_THREAD_NAME_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_HANDLE_DATA_STREAM); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MEMORY_INFO_LIST); MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpModuleCrashpadInfoList); @@ -168,7 +169,8 @@ const T* TMinidumpWritableAtLocationDescriptor( //! checking than the default implementation: //! - With a MINIDUMP_HEADER template parameter, a template specialization //! ensures that the structure’s magic number and version fields are correct. -//! - With a MINIDUMP_MEMORY_LIST, MINIDUMP_THREAD_LIST, MINIDUMP_MODULE_LIST, +//! - With a MINIDUMP_MEMORY_LIST, MINIDUMP_THREAD_LIST, +//! MINIDUMP_THREAD_NAME_LIST, MINIDUMP_MODULE_LIST, //! MINIDUMP_MEMORY_INFO_LIST, MinidumpSimpleStringDictionary, or //! MinidumpAnnotationList template parameter, template specializations //! ensure that the size given by \a location matches the size expected of a @@ -237,6 +239,12 @@ MinidumpWritableAtLocationDescriptor( const std::string& file_contents, const MINIDUMP_LOCATION_DESCRIPTOR& location); +template <> +const MINIDUMP_THREAD_NAME_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + template <> const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor( From 0662aeb83e7cb06aa45f57a7362f6be7db1afb03 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 6 Jun 2022 23:43:12 -0400 Subject: [PATCH 180/478] Fix usage of sprintf. sprintf is marked as deprecated with Xcode 14. Bug: 1331345 Change-Id: I600372d270272348d6c114112e9d7d71e75bc091 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3688301 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- client/simple_string_dictionary_test.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/client/simple_string_dictionary_test.cc b/client/simple_string_dictionary_test.cc index cc025a1741..1b4f8d2b5a 100644 --- a/client/simple_string_dictionary_test.cc +++ b/client/simple_string_dictionary_test.cc @@ -132,8 +132,10 @@ TEST(SimpleStringDictionary, Iterator) { // Set a bunch of key/value pairs like key0/value0, key1/value1, ... for (int i = 0; i < kPartitionIndex; ++i) { - sprintf(key, "key%d", i); - sprintf(value, "value%d", i); + ASSERT_LT(snprintf(key, sizeof(key), "key%d", i), + static_cast(sizeof(key))); + ASSERT_LT(snprintf(value, sizeof(value), "value%d", i), + static_cast(sizeof(value))); dict.SetKeyValue(key, value); } expected_dictionary_size = kPartitionIndex; @@ -152,8 +154,10 @@ TEST(SimpleStringDictionary, Iterator) { // Set some more key/value pairs like key59/value59, key60/value60, ... for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { - sprintf(key, "key%d", i); - sprintf(value, "value%d", i); + ASSERT_LT(snprintf(key, sizeof(key), "key%d", i), + static_cast(sizeof(key))); + ASSERT_LT(snprintf(value, sizeof(value), "value%d", i), + static_cast(sizeof(value))); dict.SetKeyValue(key, value); } expected_dictionary_size += kDictionaryCapacity - kPartitionIndex; From 339b1252417f8a6d1c0fb75c706c5329b2252a3c Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Wed, 8 Jun 2022 12:37:49 -0600 Subject: [PATCH 181/478] [minidump] Fix unaligned pointer in thread name list https://crrev.com/c/3671775/ introduced a warning (and thus, a compilation failure) on 32-bit ARM when taking the address of the RVA64 field MINIDUMP_THREAD_NAME::RvaOfThreadName: minidump/minidump_thread_name_list_writer.cc:57:23: error: taking address of packed member 'RvaOfThreadName' of class or structure 'MINIDUMP_THREAD_NAME' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member] name_->RegisterRVA(&thread_name_.RvaOfThreadName); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Indeed, MINIDUMP_THREAD_NAME's RvaOfThreadName field is not aligned, so the technique used in MinidumpWritable::Register*() of passing in a rawptr to an arbitrary struct field which is later dereferenced cannot be used for this field. This CL replaces the use of MinidumpWritable::Register*() with overriding MinidumpThreadNameWriter::WillWriteAtOffsetImpl() to directly calculate and assign thread_name_.RvaOfThreadName. Change-Id: I71e751a5b5e896b5e7277879bdbdff6e9eefe023 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3693846 Reviewed-by: Mark Mentovai Commit-Queue: Ben Hamilton Reviewed-by: Ben Hamilton --- minidump/minidump_thread_name_list_writer.cc | 30 ++++++++++++-------- minidump/minidump_thread_name_list_writer.h | 2 +- minidump/minidump_writable.h | 4 --- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/minidump/minidump_thread_name_list_writer.cc b/minidump/minidump_thread_name_list_writer.cc index 91a02d8883..a955c271de 100644 --- a/minidump/minidump_thread_name_list_writer.cc +++ b/minidump/minidump_thread_name_list_writer.cc @@ -43,18 +43,6 @@ void MinidumpThreadNameWriter::SetThreadName(const std::string& name) { name_->SetUTF8(name); } -bool MinidumpThreadNameWriter::Freeze() { - DCHECK_EQ(state(), kStateMutable); - - if (!MinidumpWritable::Freeze()) { - return false; - } - - name_->RegisterRVA(&thread_name_.RvaOfThreadName); - - return true; -} - size_t MinidumpThreadNameWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); @@ -75,6 +63,24 @@ std::vector MinidumpThreadNameWriter::Children() { return children; } +bool MinidumpThreadNameWriter::WillWriteAtOffsetImpl(FileOffset offset) { + DCHECK_EQ(state(), kStateFrozen); + + // This cannot use RegisterRVA(&thread_name_.RvaOfThreadName), since + // &MINIDUMP_THREAD_NAME_LIST::RvaOfThreadName is not aligned on a pointer + // boundary, so it causes failures on 32-bit ARM. + // + // Instead, manually update the RVA64 to the current file offset since the + // child thread_name_ will write its contents at that offset. + decltype(thread_name_.RvaOfThreadName) local_rva_of_thread_name; + if (!AssignIfInRange(&local_rva_of_thread_name, offset)) { + LOG(ERROR) << "offset " << offset << " out of range"; + return false; + } + thread_name_.RvaOfThreadName = local_rva_of_thread_name; + return MinidumpWritable::WillWriteAtOffsetImpl(offset); +} + bool MinidumpThreadNameWriter::WriteObject(FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); diff --git a/minidump/minidump_thread_name_list_writer.h b/minidump/minidump_thread_name_list_writer.h index 9cfe2d087d..5afab9812c 100644 --- a/minidump/minidump_thread_name_list_writer.h +++ b/minidump/minidump_thread_name_list_writer.h @@ -61,9 +61,9 @@ class MinidumpThreadNameWriter final : public internal::MinidumpWritable { private: // MinidumpWritable: - bool Freeze() override; size_t SizeOfObject() override; std::vector Children() override; + bool WillWriteAtOffsetImpl(FileOffset offset) override; bool WriteObject(FileWriterInterface* file_writer) override; MINIDUMP_THREAD_NAME thread_name_; diff --git a/minidump/minidump_writable.h b/minidump/minidump_writable.h index 284b9f0799..15d9241e08 100644 --- a/minidump/minidump_writable.h +++ b/minidump/minidump_writable.h @@ -70,8 +70,6 @@ class MinidumpWritable { // This is public instead of protected because objects of derived classes need // to be able to register their own pointers with distinct objects. void RegisterRVA(RVA* rva); - - //! \brief 64-bit specialization of RegisterRVA. void RegisterRVA(RVA64* rva); //! \brief Registers a location descriptor as one that should point to the @@ -91,8 +89,6 @@ class MinidumpWritable { // to be able to register their own pointers with distinct objects. void RegisterLocationDescriptor( MINIDUMP_LOCATION_DESCRIPTOR* location_descriptor); - - //! \brief 64-bit specialization of RegisterLocationDescriptor. void RegisterLocationDescriptor( MINIDUMP_LOCATION_DESCRIPTOR64* location_descriptor64); From 816c5572b8c6d7aac8fb85db770496bc1f1da439 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 8 Jun 2022 19:45:54 -0400 Subject: [PATCH 182/478] Lazy load settings in CrashReportDatabase. Before this patch, settings.dat is read from and written to during database initialization. This happens within Crashpad for iOS, and within Chrome during startup here: https://source.chromium.org/chromium/chromium/src/+/main:components/crash/core/app/crashpad.cc;l=209 These are blocking calls on the main thread. CrashReportDatabaseMac::Initialize will still fail if the various directory create/ensure calls fail. Change-Id: Ic665884d1f41caa853aba9b29b6fb2c14b2cda15 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3674639 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen --- client/crash_report_database_generic.cc | 16 ++++++----- client/crash_report_database_mac.mm | 20 ++++++++------ client/crash_report_database_test.cc | 35 +++++++++++++++++++++++++ client/crash_report_database_win.cc | 21 ++++++++++----- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index 9d48b68be5..c4e0401096 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -257,8 +257,16 @@ class CrashReportDatabaseGeneric : public CrashReportDatabase { // Writes the metadata for report to the filesystem at path. static bool WriteMetadata(const base::FilePath& path, const Report& report); + Settings& SettingsInternal() { + if (!settings_init_) + settings_.Initialize(base_dir_.Append(kSettings)); + settings_init_ = true; + return settings_; + } + base::FilePath base_dir_; Settings settings_; + bool settings_init_ = false; InitializationStateDcheck initialized_; }; @@ -289,10 +297,6 @@ bool CrashReportDatabaseGeneric::Initialize(const base::FilePath& path, return false; } - if (!settings_.Initialize(base_dir_.Append(kSettings))) { - return false; - } - INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -317,7 +321,7 @@ base::FilePath CrashReportDatabaseGeneric::DatabasePath() { Settings* CrashReportDatabaseGeneric::GetSettings() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return &settings_; + return &SettingsInternal(); } OperationStatus CrashReportDatabaseGeneric::PrepareNewCrashReport( @@ -588,7 +592,7 @@ OperationStatus CrashReportDatabaseGeneric::RecordUploadAttempt( return kDatabaseError; } - if (!settings_.SetLastUploadAttemptTime(now)) { + if (!SettingsInternal().SetLastUploadAttemptTime(now)) { return kDatabaseError; } diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 9095392307..4c9e5e72e8 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -262,20 +262,27 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, // Cleans any attachments that have no associated report in any state. void CleanOrphanedAttachments(); + Settings& SettingsInternal() { + if (!settings_init_) + settings_.Initialize(base_dir_.Append(kSettings)); + settings_init_ = true; + return settings_; + } + base::FilePath base_dir_; Settings settings_; + bool settings_init_; bool xattr_new_names_; InitializationStateDcheck initialized_; }; - CrashReportDatabaseMac::CrashReportDatabaseMac(const base::FilePath& path) : CrashReportDatabase(), base_dir_(path), settings_(), + settings_init_(false), xattr_new_names_(false), - initialized_() { -} + initialized_() {} CrashReportDatabaseMac::~CrashReportDatabaseMac() {} @@ -301,9 +308,6 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return false; } - if (!settings_.Initialize(base_dir_.Append(kSettings))) - return false; - // Do an xattr operation as the last step, to ensure the filesystem has // support for them. This xattr also serves as a marker for whether the // database uses old or new xattr names. @@ -334,7 +338,7 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, Settings* CrashReportDatabaseMac::GetSettings() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return &settings_; + return &SettingsInternal(); } CrashReportDatabase::OperationStatus @@ -527,7 +531,7 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return kDatabaseError; } - if (!settings_.SetLastUploadAttemptTime(now)) { + if (!SettingsInternal().SetLastUploadAttemptTime(now)) { return kDatabaseError; } diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index d75ab355b9..bdb6dc242c 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -185,6 +185,41 @@ TEST_F(CrashReportDatabaseTest, Initialize) { EXPECT_FALSE(db); } +TEST_F(CrashReportDatabaseTest, Settings) { + // Initialize three databases and ensure settings.dat isn't created yet. + ASSERT_TRUE(db()); + + base::FilePath settings_path = + path().Append(FILE_PATH_LITERAL("settings.dat")); + EXPECT_FALSE(FileExists(settings_path)); + + std::unique_ptr db2 = + CrashReportDatabase::Initialize(path()); + ASSERT_TRUE(db2); + EXPECT_FALSE(FileExists(settings_path)); + + std::unique_ptr db3 = + CrashReportDatabase::Initialize(path()); + ASSERT_TRUE(db3); + EXPECT_FALSE(FileExists(settings_path)); + + // Ensure settings.dat exists after getter. + Settings* settings = db3->GetSettings(); + ASSERT_TRUE(settings); + EXPECT_TRUE(FileExists(settings_path)); + + time_t last_upload_attempt_time = 42; + ASSERT_TRUE(settings->SetLastUploadAttemptTime(last_upload_attempt_time)); + + // Ensure the first two databases read the same value. + ASSERT_TRUE( + db2->GetSettings()->GetLastUploadAttemptTime(&last_upload_attempt_time)); + EXPECT_EQ(last_upload_attempt_time, 42); + ASSERT_TRUE( + db()->GetSettings()->GetLastUploadAttemptTime(&last_upload_attempt_time)); + EXPECT_EQ(last_upload_attempt_time, 42); +} + TEST_F(CrashReportDatabaseTest, NewCrashReport) { std::unique_ptr new_report; EXPECT_EQ(db()->PrepareNewCrashReport(&new_report), diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 6331f65082..e16aa104fb 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -662,13 +662,25 @@ class CrashReportDatabaseWin : public CrashReportDatabase { std::unique_ptr AcquireMetadata(); + Settings& SettingsInternal() { + if (!settings_init_) + settings_.Initialize(base_dir_.Append(kSettings)); + settings_init_ = true; + return settings_; + } + base::FilePath base_dir_; Settings settings_; + bool settings_init_; InitializationStateDcheck initialized_; }; CrashReportDatabaseWin::CrashReportDatabaseWin(const base::FilePath& path) - : CrashReportDatabase(), base_dir_(path), settings_(), initialized_() {} + : CrashReportDatabase(), + base_dir_(path), + settings_(), + settings_init_(false), + initialized_() {} CrashReportDatabaseWin::~CrashReportDatabaseWin() { } @@ -691,9 +703,6 @@ bool CrashReportDatabaseWin::Initialize(bool may_create) { if (!CreateDirectoryIfNecessary(AttachmentsRootPath())) return false; - if (!settings_.Initialize(base_dir_.Append(kSettings))) - return false; - INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -704,7 +713,7 @@ base::FilePath CrashReportDatabaseWin::DatabasePath() { Settings* CrashReportDatabaseWin::GetSettings() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return &settings_; + return &SettingsInternal(); } OperationStatus CrashReportDatabaseWin::PrepareNewCrashReport( @@ -848,7 +857,7 @@ OperationStatus CrashReportDatabaseWin::RecordUploadAttempt( report->upload_explicitly_requested; } - if (!settings_.SetLastUploadAttemptTime(now)) + if (!SettingsInternal().SetLastUploadAttemptTime(now)) return kDatabaseError; return kNoError; From 0a14d52dad27441528475f553efe6d612e0643cc Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 10 Jun 2022 09:55:32 -0400 Subject: [PATCH 183/478] Update buildtools (gn and clang-format) This updates buildtools to 8b16338d17cd. gn has migrated out of buildtools and into its own cipd package, so gn is pulled at 2ecd43a10266 (current). This provides a mac-x86_64 or mac-arm64 gn as appropriate for the host CPU architecture. The buildtools update also brings distinct clang-format executables for mac-x86_64 and mac-arm64 as appropriate. Change-Id: I4162b093cfe8d5a2ba66ba62f6462813ea489dbd Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3700190 Commit-Queue: Mark Mentovai Reviewed-by: Justin Cohen --- DEPS | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 229922376b..9829da3433 100644 --- a/DEPS +++ b/DEPS @@ -14,6 +14,7 @@ vars = { 'chromium_git': 'https://chromium.googlesource.com', + 'gn_version': 'git_revision:2ecd43a10266bd091c98e6dcde507c64f6a0dad3', 'pull_linux_clang': False, 'pull_win_toolchain': False, # Controls whether crashpad/build/ios/setup-ios-gn.py is run as part of @@ -25,7 +26,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - '9e121212d42be62a7cce38072f925f8398d11e49', + '8b16338d17cd71b04a6ba28da7322ab6739892c2', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '727e556705278598fce683522beedbb9946bfda0', @@ -47,7 +48,37 @@ deps = { Var('chromium_git') + '/chromium/src/third_party/zlib@' + '13dc246a58e4b72104d35f9b1809af95221ebda7', - # CIPD packages below. + # CIPD packages. + 'buildtools/linux64': { + 'packages': [ + { + 'package': 'gn/gn/linux-amd64', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "linux"', + }, + 'buildtools/mac': { + 'packages': [ + { + 'package': 'gn/gn/mac-${{arch}}', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "mac"', + }, + 'buildtools/win': { + 'packages': [ + { + 'package': 'gn/gn/windows-amd64', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "win"', + }, 'crashpad/third_party/linux/clang/linux-amd64': { 'packages': [ { @@ -125,7 +156,9 @@ hooks = [ '--no_auth', '--bucket=chromium-clang-format', '--sha1_file', - 'buildtools/mac/clang-format.sha1', + 'buildtools/mac/clang-format.{host_cpu}.sha1', + '--output', + 'buildtools/mac/clang-format', ], }, { From ed8cfeb2cd45f3ee3c8829cde9f168d98b0ed064 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Mon, 13 Jun 2022 14:44:24 -0600 Subject: [PATCH 184/478] [snapshot] Add support for thread names This CL adds a new method ThreadSnapshot::ThreadName(), implements it in each snapshot implementation, and adds tests for iOS, macOS, Linux, Windows, and Fuchsia. Bug: crashpad:327 Change-Id: I35031975223854c19d977e057dd026a40d33fd41 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3671776 Reviewed-by: Mark Mentovai Commit-Queue: Ben Hamilton Reviewed-by: Ben Hamilton --- .../in_process_intermediate_dump_handler.cc | 16 +++ ..._process_intermediate_dump_handler_test.cc | 4 + minidump/minidump_file_writer.cc | 17 ++++ minidump/minidump_thread_name_list_writer.cc | 83 ++++++++++------ minidump/minidump_thread_name_list_writer.h | 60 ++++++++++-- .../minidump_thread_name_list_writer_test.cc | 59 +++++++++++ .../fuchsia/process_reader_fuchsia_test.cc | 31 +++++- snapshot/fuchsia/thread_snapshot_fuchsia.cc | 7 ++ snapshot/fuchsia/thread_snapshot_fuchsia.h | 4 + ...ess_snapshot_ios_intermediate_dump_test.cc | 2 + .../thread_snapshot_ios_intermediate_dump.cc | 7 ++ .../thread_snapshot_ios_intermediate_dump.h | 4 + snapshot/linux/process_reader_linux.cc | 19 ++++ snapshot/linux/process_reader_linux.h | 1 + snapshot/linux/process_reader_linux_test.cc | 62 ++++++++++-- snapshot/linux/thread_snapshot_linux.cc | 7 ++ snapshot/linux/thread_snapshot_linux.h | 2 + snapshot/mac/process_reader_mac.cc | 15 +++ snapshot/mac/process_reader_mac.h | 1 + snapshot/mac/process_reader_mac_test.cc | 78 +++++++++++++-- snapshot/mac/thread_snapshot_mac.cc | 10 +- snapshot/mac/thread_snapshot_mac.h | 4 + .../minidump/process_snapshot_minidump.cc | 60 +++++++++++- snapshot/minidump/process_snapshot_minidump.h | 5 + .../process_snapshot_minidump_test.cc | 98 +++++++++++++++++++ snapshot/minidump/thread_snapshot_minidump.cc | 18 +++- snapshot/minidump/thread_snapshot_minidump.h | 9 +- .../sanitized/thread_snapshot_sanitized.cc | 4 + .../sanitized/thread_snapshot_sanitized.h | 3 + snapshot/test/test_thread_snapshot.cc | 4 + snapshot/test/test_thread_snapshot.h | 6 ++ snapshot/thread_snapshot.h | 4 + snapshot/win/process_reader_win.cc | 28 ++++-- snapshot/win/process_reader_win.h | 2 + snapshot/win/process_reader_win_test.cc | 51 +++++++++- snapshot/win/process_snapshot_win.cc | 3 +- snapshot/win/thread_snapshot_win.cc | 5 + snapshot/win/thread_snapshot_win.h | 1 + test/BUILD.gn | 15 ++- test/scoped_set_thread_name.h | 46 +++++++++ test/scoped_set_thread_name_fuchsia.cc | 61 ++++++++++++ test/scoped_set_thread_name_posix.cc | 80 +++++++++++++++ test/scoped_set_thread_name_win.cc | 56 +++++++++++ util/ios/ios_intermediate_dump_format.h | 1 + 44 files changed, 974 insertions(+), 79 deletions(-) create mode 100644 test/scoped_set_thread_name.h create mode 100644 test/scoped_set_thread_name_fuchsia.cc create mode 100644 test/scoped_set_thread_name_posix.cc create mode 100644 test/scoped_set_thread_name_win.cc diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index 2869c2174f..e7e9003e3b 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -811,6 +811,22 @@ void InProcessIntermediateDumpHandler::WriteThreadInfo( CRASHPAD_RAW_LOG_ERROR(kr, "thread_info::THREAD_BASIC_INFO"); } + thread_extended_info extended_info; + count = THREAD_EXTENDED_INFO_COUNT; + kr = thread_info(thread, + THREAD_EXTENDED_INFO, + reinterpret_cast(&extended_info), + &count); + if (kr == KERN_SUCCESS) { + WritePropertyBytes( + writer, + IntermediateDumpKey::kThreadName, + reinterpret_cast(extended_info.pth_name), + strnlen(extended_info.pth_name, sizeof(extended_info.pth_name))); + } else { + CRASHPAD_RAW_LOG_ERROR(kr, "thread_info::THREAD_EXTENDED_INFO"); + } + thread_precedence_policy precedence; count = THREAD_PRECEDENCE_POLICY_COUNT; boolean_t get_default = FALSE; diff --git a/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/client/ios_handler/in_process_intermediate_dump_handler_test.cc index bccc930d34..f1d8a546a5 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler_test.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler_test.cc @@ -26,6 +26,7 @@ #include "client/simple_string_dictionary.h" #include "gtest/gtest.h" #include "snapshot/ios/process_snapshot_ios_intermediate_dump.h" +#include "test/scoped_set_thread_name.h" #include "test/scoped_temp_dir.h" #include "test/test_paths.h" #include "util/file/filesystem.h" @@ -206,6 +207,8 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestAnnotations) { } TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) { + const ScopedSetThreadName scoped_set_thread_name("TestThreads"); + WriteReport(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); @@ -221,6 +224,7 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) { &count), 0); EXPECT_EQ(threads[0]->ThreadID(), identifier_info.thread_id); + EXPECT_EQ(threads[0]->ThreadName(), "TestThreads"); } TEST_F(InProcessIntermediateDumpHandlerTest, TestProcess) { diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 43abca84c0..bc5bf022d7 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -26,6 +26,7 @@ #include "minidump/minidump_module_writer.h" #include "minidump/minidump_system_info_writer.h" #include "minidump/minidump_thread_id_map.h" +#include "minidump/minidump_thread_name_list_writer.h" #include "minidump/minidump_thread_writer.h" #include "minidump/minidump_unloaded_module_writer.h" #include "minidump/minidump_user_extension_stream_data_source.h" @@ -34,6 +35,7 @@ #include "snapshot/exception_snapshot.h" #include "snapshot/module_snapshot.h" #include "snapshot/process_snapshot.h" +#include "snapshot/thread_snapshot.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h" @@ -94,6 +96,21 @@ void MinidumpFileWriter::InitializeFromSnapshot( add_stream_result = AddStream(std::move(thread_list)); DCHECK(add_stream_result); + bool has_thread_name = false; + for (const ThreadSnapshot* thread_snapshot : process_snapshot->Threads()) { + if (!thread_snapshot->ThreadName().empty()) { + has_thread_name = true; + break; + } + } + if (has_thread_name) { + auto thread_name_list = std::make_unique(); + thread_name_list->InitializeFromSnapshot(process_snapshot->Threads(), + thread_id_map); + add_stream_result = AddStream(std::move(thread_name_list)); + DCHECK(add_stream_result); + } + const ExceptionSnapshot* exception_snapshot = process_snapshot->Exception(); if (exception_snapshot) { auto exception = std::make_unique(); diff --git a/minidump/minidump_thread_name_list_writer.cc b/minidump/minidump_thread_name_list_writer.cc index a955c271de..6f49f0cc99 100644 --- a/minidump/minidump_thread_name_list_writer.cc +++ b/minidump/minidump_thread_name_list_writer.cc @@ -17,21 +17,47 @@ #include #include "base/logging.h" +#include "minidump/minidump_thread_id_map.h" +#include "snapshot/thread_snapshot.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h" namespace crashpad { MinidumpThreadNameWriter::MinidumpThreadNameWriter() - : MinidumpWritable(), thread_name_(), name_() {} + : MinidumpWritable(), rva_of_thread_name_(), thread_id_(), name_() {} MinidumpThreadNameWriter::~MinidumpThreadNameWriter() {} -const MINIDUMP_THREAD_NAME* MinidumpThreadNameWriter::MinidumpThreadName() - const { +void MinidumpThreadNameWriter::InitializeFromSnapshot( + const ThreadSnapshot* thread_snapshot, + const MinidumpThreadIDMap& thread_id_map) { + DCHECK_EQ(state(), kStateMutable); + + const auto it = thread_id_map.find(thread_snapshot->ThreadID()); + DCHECK(it != thread_id_map.end()); + SetThreadId(it->second); + SetThreadName(thread_snapshot->ThreadName()); +} + +RVA64 MinidumpThreadNameWriter::RvaOfThreadName() const { DCHECK_EQ(state(), kStateWritable); - return &thread_name_; + return rva_of_thread_name_; +} + +uint32_t MinidumpThreadNameWriter::ThreadId() const { + DCHECK_EQ(state(), kStateWritable); + + return thread_id_; +} + +bool MinidumpThreadNameWriter::Freeze() { + DCHECK_EQ(state(), kStateMutable); + + name_->RegisterRVA(&rva_of_thread_name_); + + return MinidumpWritable::Freeze(); } void MinidumpThreadNameWriter::SetThreadName(const std::string& name) { @@ -46,10 +72,9 @@ void MinidumpThreadNameWriter::SetThreadName(const std::string& name) { size_t MinidumpThreadNameWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); - // This object doesn’t directly write anything itself. Its - // MINIDUMP_THREAD_NAME is written by its parent as part of a - // MINIDUMP_THREAD_NAME_LIST, and its children are responsible for writing - // themselves. + // This object doesn’t directly write anything itself. Its parent writes the + // MINIDUMP_THREAD_NAME objects as part of a MINIDUMP_THREAD_NAME_LIST, and + // its children are responsible for writing themselves. return 0; } @@ -63,24 +88,6 @@ std::vector MinidumpThreadNameWriter::Children() { return children; } -bool MinidumpThreadNameWriter::WillWriteAtOffsetImpl(FileOffset offset) { - DCHECK_EQ(state(), kStateFrozen); - - // This cannot use RegisterRVA(&thread_name_.RvaOfThreadName), since - // &MINIDUMP_THREAD_NAME_LIST::RvaOfThreadName is not aligned on a pointer - // boundary, so it causes failures on 32-bit ARM. - // - // Instead, manually update the RVA64 to the current file offset since the - // child thread_name_ will write its contents at that offset. - decltype(thread_name_.RvaOfThreadName) local_rva_of_thread_name; - if (!AssignIfInRange(&local_rva_of_thread_name, offset)) { - LOG(ERROR) << "offset " << offset << " out of range"; - return false; - } - thread_name_.RvaOfThreadName = local_rva_of_thread_name; - return MinidumpWritable::WillWriteAtOffsetImpl(offset); -} - bool MinidumpThreadNameWriter::WriteObject(FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); @@ -96,6 +103,19 @@ MinidumpThreadNameListWriter::MinidumpThreadNameListWriter() MinidumpThreadNameListWriter::~MinidumpThreadNameListWriter() {} +void MinidumpThreadNameListWriter::InitializeFromSnapshot( + const std::vector& thread_snapshots, + const MinidumpThreadIDMap& thread_id_map) { + DCHECK_EQ(state(), kStateMutable); + DCHECK(thread_names_.empty()); + + for (const ThreadSnapshot* thread_snapshot : thread_snapshots) { + auto thread = std::make_unique(); + thread->InitializeFromSnapshot(thread_snapshot, thread_id_map); + AddThreadName(std::move(thread)); + } +} + void MinidumpThreadNameListWriter::AddThreadName( std::unique_ptr thread_name) { DCHECK_EQ(state(), kStateMutable); @@ -150,10 +170,15 @@ bool MinidumpThreadNameListWriter::WriteObject( std::vector iovecs(1, iov); iovecs.reserve(thread_names_.size() + 1); + std::vector minidump_thread_names; + minidump_thread_names.reserve(thread_names_.size()); for (const auto& thread_name : thread_names_) { - iov.iov_base = thread_name->MinidumpThreadName(); - iov.iov_len = sizeof(MINIDUMP_THREAD_NAME); - iovecs.emplace_back(iov); + auto& minidump_thread_name = minidump_thread_names.emplace_back(); + minidump_thread_name.ThreadId = thread_name->ThreadId(); + minidump_thread_name.RvaOfThreadName = thread_name->RvaOfThreadName(); + iov.iov_base = &minidump_thread_name; + iov.iov_len = sizeof(minidump_thread_name); + iovecs.push_back(iov); } return file_writer->WriteIoVec(&iovecs); diff --git a/minidump/minidump_thread_name_list_writer.h b/minidump/minidump_thread_name_list_writer.h index 5afab9812c..f573111c49 100644 --- a/minidump/minidump_thread_name_list_writer.h +++ b/minidump/minidump_thread_name_list_writer.h @@ -25,6 +25,7 @@ #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_string_writer.h" +#include "minidump/minidump_thread_id_map.h" #include "minidump/minidump_writable.h" namespace crashpad { @@ -45,28 +46,57 @@ class MinidumpThreadNameWriter final : public internal::MinidumpWritable { ~MinidumpThreadNameWriter() override; - //! \brief Returns a MINIDUMP_THREAD_NAME referencing this object’s data. + //! \brief Initializes the MINIDUMP_THREAD_NAME based on \a thread_snapshot. //! - //! This method is expected to be called by a MinidumpThreadNameListWriter in - //! order to obtain a MINIDUMP_THREAD_NAME to include in its list. + //! \param[in] thread_snapshot The thread snapshot to use as source data. + //! \param[in] thread_id_map A MinidumpThreadIDMap to be consulted to + //! determine the 32-bit minidump thread ID to use for \a thread_snapshot. //! - //! \note Valid in #kStateWritable. - const MINIDUMP_THREAD_NAME* MinidumpThreadName() const; + //! \note Valid in #kStateMutable. + void InitializeFromSnapshot(const ThreadSnapshot* thread_snapshot, + const MinidumpThreadIDMap& thread_id_map); - //! \brief Sets MINIDUMP_THREAD_NAME::ThreadId. - void SetThreadId(uint32_t thread_id) { thread_name_.ThreadId = thread_id; } + //! \brief Sets the ThreadId for MINIDUMP_THREAD_NAME::ThreadId. + void SetThreadId(uint32_t thread_id) { thread_id_ = thread_id; } + + //! \brief Gets the ThreadId for MINIDUMP_THREAD_NAME::ThreadId. + //! + //! \note Valid in #kStateWritable. + uint32_t ThreadId() const; //! \brief Sets MINIDUMP_THREAD_NAME::RvaOfThreadName. void SetThreadName(const std::string& thread_name); + //! \brief Returns an RVA64 which has been updated with the relative address + //! of the thread name. + //! + //! This method is expected to be called by a MinidumpThreadNameListWriter in + //! order to obtain the RVA64 of the thread name. + //! + //! \note Valid in #kStateWritable. + RVA64 RvaOfThreadName() const; + private: // MinidumpWritable: + bool Freeze() override; size_t SizeOfObject() override; std::vector Children() override; - bool WillWriteAtOffsetImpl(FileOffset offset) override; bool WriteObject(FileWriterInterface* file_writer) override; - MINIDUMP_THREAD_NAME thread_name_; + // This exists as a separate field so MinidumpWritable::RegisterRVA() can be + // used on a guaranteed-aligned pointer (MINIDUMP_THREAD_NAME::RvaOfThreadName + // is not 64-bit aligned, causing issues on ARM). + RVA64 rva_of_thread_name_; + + // Although this class manages the data for a MINIDUMP_THREAD_NAME, it does + // not directly hold a MINIDUMP_THREAD_NAME, as that struct contains a + // non-aligned RVA64 field which prevents it use with + // MinidumpWritable::RegisterRVA(). + // + // Instead, this class individually holds the fields of the + // MINIDUMP_THREAD_NAME which are fetched by MinidumpThreadNameListWriter. + uint32_t thread_id_; + std::unique_ptr name_; }; @@ -83,6 +113,18 @@ class MinidumpThreadNameListWriter final ~MinidumpThreadNameListWriter() override; + //! \brief Adds an initialized MINIDUMP_THREAD_NAME for each thread in \a + //! thread_snapshots to the MINIDUMP_THREAD_NAME_LIST. + //! + //! \param[in] thread_snapshots The thread snapshots to use as source data. + //! \param[in] thread_id_map A MinidumpThreadIDMap previously built by + //! MinidumpThreadListWriter::InitializeFromSnapshot(). + //! + //! \note Valid in #kStateMutable. + void InitializeFromSnapshot( + const std::vector& thread_snapshots, + const MinidumpThreadIDMap& thread_id_map); + //! \brief Adds a MinidumpThreadNameWriter to the MINIDUMP_THREAD_LIST. //! //! This object takes ownership of \a thread_name and becomes its parent in diff --git a/minidump/minidump_thread_name_list_writer_test.cc b/minidump/minidump_thread_name_list_writer_test.cc index b61b1bb4da..265c12e684 100644 --- a/minidump/minidump_thread_name_list_writer_test.cc +++ b/minidump/minidump_thread_name_list_writer_test.cc @@ -24,6 +24,7 @@ #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_file_writer.h" +#include "minidump/minidump_system_info_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" @@ -137,6 +138,64 @@ TEST(MinidumpThreadNameListWriter, OneThread) { kThreadName)); } +TEST(MinidumpThreadNameListWriter, OneThreadWithLeadingPadding) { + MinidumpFileWriter minidump_file_writer; + + // Add a stream before the MINIDUMP_THREAD_NAME_LIST to ensure the thread name + // MINIDUMP_STRING requires leading padding to align to a 4-byte boundary. + auto system_info_writer = std::make_unique(); + system_info_writer->SetCSDVersion(""); + ASSERT_TRUE(minidump_file_writer.AddStream(std::move(system_info_writer))); + + auto thread_list_writer = std::make_unique(); + + constexpr uint32_t kThreadID = 0x11111111; + const std::string kThreadName = "ariadne"; + + auto thread_name_list_writer = + std::make_unique(); + auto thread_name_writer = std::make_unique(); + thread_name_writer->SetThreadId(kThreadID); + thread_name_writer->SetThreadName(kThreadName); + thread_name_list_writer->AddThreadName(std::move(thread_name_writer)); + + ASSERT_TRUE( + minidump_file_writer.AddStream(std::move(thread_name_list_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + ASSERT_GT(string_file.string().size(), + sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + + sizeof(MINIDUMP_THREAD_NAME_LIST) + + 1 * sizeof(MINIDUMP_THREAD_NAME)); + + const uint32_t kExpectedStreams = 2; + const MINIDUMP_DIRECTORY* directory; + const MINIDUMP_HEADER* header = + MinidumpHeaderAtStart(string_file.string(), &directory); + ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, kExpectedStreams, 0)); + ASSERT_TRUE(directory); + + ASSERT_EQ(directory[0].StreamType, kMinidumpStreamTypeSystemInfo); + ASSERT_EQ(directory[1].StreamType, kMinidumpStreamTypeThreadNameList); + + const MINIDUMP_THREAD_NAME_LIST* thread_name_list = + MinidumpWritableAtLocationDescriptor( + string_file.string(), directory[1].Location); + ASSERT_TRUE(thread_name_list); + + EXPECT_EQ(thread_name_list->NumberOfThreadNames, 1u); + + MINIDUMP_THREAD_NAME expected = {}; + expected.ThreadId = kThreadID; + + ASSERT_NO_FATAL_FAILURE(ExpectThreadName(&expected, + &thread_name_list->ThreadNames[0], + string_file.string(), + kThreadName)); +} + TEST(MinidumpThreadNameListWriter, TwoThreads_DifferentNames) { MinidumpFileWriter minidump_file_writer; auto thread_list_writer = std::make_unique(); diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index 362be5bd46..3c8f827001 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -22,8 +22,10 @@ #include +#include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/multiprocess_exec.h" +#include "test/scoped_set_thread_name.h" #include "test/test_paths.h" #include "util/fuchsia/scoped_task_suspend.h" @@ -32,6 +34,8 @@ namespace test { namespace { TEST(ProcessReaderFuchsia, SelfBasic) { + const ScopedSetThreadName scoped_set_thread_name("SelfBasic"); + ProcessReaderFuchsia process_reader; ASSERT_TRUE(process_reader.Initialize(*zx::process::self())); @@ -75,7 +79,7 @@ TEST(ProcessReaderFuchsia, SelfBasic) { ZX_OK); EXPECT_EQ(threads[0].id, info.koid); EXPECT_EQ(threads[0].state, ZX_THREAD_STATE_RUNNING); - EXPECT_EQ(threads[0].name, "initial-thread"); + EXPECT_EQ(threads[0].name, "SelfBasic"); } constexpr char kTestMemory[] = "Read me from another process"; @@ -118,27 +122,44 @@ TEST(ProcessReaderFuchsia, ChildBasic) { test.Run(); } +struct ThreadData { + zx_handle_t port; + std::string name; +}; + void* SignalAndSleep(void* arg) { + const ThreadData* thread_data = reinterpret_cast(arg); + const ScopedSetThreadName scoped_set_thread_name(thread_data->name); zx_port_packet_t packet = {}; packet.type = ZX_PKT_TYPE_USER; - zx_port_queue(*reinterpret_cast(arg), &packet); + zx_port_queue(thread_data->port, &packet); zx_nanosleep(ZX_TIME_INFINITE); return nullptr; } CRASHPAD_CHILD_TEST_MAIN(ProcessReaderChildThreadsTestMain) { + const ScopedSetThreadName scoped_set_thread_name( + "ProcessReaderChildThreadsTest-Main"); + // Create 5 threads with stack sizes of 4096, 8192, ... zx_handle_t port; zx_status_t status = zx_port_create(0, &port); EXPECT_EQ(status, ZX_OK); constexpr size_t kNumThreads = 5; + struct ThreadData thread_data[kNumThreads] = {{0}}; + for (size_t i = 0; i < kNumThreads; ++i) { + thread_data[i] = { + .port = port, + .name = base::StringPrintf("ProcessReaderChildThreadsTest-%zu", i + 1), + }; pthread_attr_t attr; EXPECT_EQ(pthread_attr_init(&attr), 0); EXPECT_EQ(pthread_attr_setstacksize(&attr, (i + 1) * 4096), 0); pthread_t thread; - EXPECT_EQ(pthread_create(&thread, &attr, &SignalAndSleep, &port), 0); + EXPECT_EQ(pthread_create(&thread, &attr, &SignalAndSleep, &thread_data[i]), + 0); } // Wait until all threads are ready. @@ -179,10 +200,14 @@ class ThreadsChildTest : public MultiprocessExec { const auto& threads = process_reader.Threads(); EXPECT_EQ(threads.size(), 6u); + EXPECT_EQ(threads[0].name, "ProcessReaderChildThreadsTest-main"); + for (size_t i = 1; i < 6; ++i) { ASSERT_GT(threads[i].stack_regions.size(), 0u); EXPECT_GT(threads[i].stack_regions[0].size(), 0u); EXPECT_LE(threads[i].stack_regions[0].size(), i * 4096u); + EXPECT_EQ(threads[i].name, + base::StringPrintf("ProcessReaderChildThreadsTest-%zu", i)); } } }; diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.cc b/snapshot/fuchsia/thread_snapshot_fuchsia.cc index 369203ae3c..b12ee86152 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.cc @@ -25,6 +25,7 @@ ThreadSnapshotFuchsia::ThreadSnapshotFuchsia() context_arch_(), context_(), stack_(), + thread_name_(), thread_id_(ZX_KOID_INVALID), thread_specific_data_address_(0), initialized_() {} @@ -60,6 +61,7 @@ bool ThreadSnapshotFuchsia::Initialize( // TODO(scottmg): Handle split stack by adding other parts to ExtraMemory(). } + thread_name_ = thread.name; thread_id_ = thread.id; INITIALIZATION_STATE_SET_VALID(initialized_); @@ -81,6 +83,11 @@ uint64_t ThreadSnapshotFuchsia::ThreadID() const { return thread_id_; } +std::string ThreadSnapshotFuchsia::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_name_; +} + int ThreadSnapshotFuchsia::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); // There is not (currently) a suspend count for threads on Fuchsia. diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.h b/snapshot/fuchsia/thread_snapshot_fuchsia.h index b91a514d92..5c804fb107 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.h +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.h @@ -18,6 +18,8 @@ #include #include +#include + #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/fuchsia/process_reader_fuchsia.h" @@ -56,6 +58,7 @@ class ThreadSnapshotFuchsia final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -71,6 +74,7 @@ class ThreadSnapshotFuchsia final : public ThreadSnapshot { #endif CPUContext context_; MemorySnapshotGeneric stack_; + std::string thread_name_; zx_koid_t thread_id_; zx_vaddr_t thread_specific_data_address_; InitializationStateDcheck initialized_; diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 34c34f80b1..0a170e7bf7 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -392,6 +392,7 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { Key::kThreadContextMemoryRegionData, "string", 6)); } } + EXPECT_TRUE(writer->AddPropertyBytes(Key::kThreadName, "ariadne", 7)); } } @@ -411,6 +412,7 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { uint64_t thread_id = 1; for (auto thread : threads) { EXPECT_EQ(thread->ThreadID(), thread_id); + EXPECT_EQ(thread->ThreadName(), "ariadne"); EXPECT_EQ(thread->SuspendCount(), 666); EXPECT_EQ(thread->Priority(), 5); EXPECT_EQ(thread->ThreadSpecificDataAddress(), thread_id++); diff --git a/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc b/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc index ed7b28aa49..40387fa0dc 100644 --- a/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc +++ b/snapshot/ios/thread_snapshot_ios_intermediate_dump.cc @@ -75,6 +75,7 @@ ThreadSnapshotIOSIntermediateDump::ThreadSnapshotIOSIntermediateDump() #endif context_(), stack_(), + thread_name_(), thread_id_(0), thread_specific_data_address_(0), suspend_count_(0), @@ -100,6 +101,7 @@ bool ThreadSnapshotIOSIntermediateDump::Initialize( GetDataValueFromMap(thread_data, Key::kThreadID, &thread_id_); GetDataValueFromMap( thread_data, Key::kThreadDataAddress, &thread_specific_data_address_); + GetDataStringFromMap(thread_data, Key::kThreadName, &thread_name_); #if defined(ARCH_CPU_X86_64) typedef x86_thread_state64_t thread_state_type; @@ -218,6 +220,11 @@ uint64_t ThreadSnapshotIOSIntermediateDump::ThreadID() const { return thread_id_; } +std::string ThreadSnapshotIOSIntermediateDump::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_name_; +} + int ThreadSnapshotIOSIntermediateDump::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return suspend_count_; diff --git a/snapshot/ios/thread_snapshot_ios_intermediate_dump.h b/snapshot/ios/thread_snapshot_ios_intermediate_dump.h index cf9ccec023..dafa455826 100644 --- a/snapshot/ios/thread_snapshot_ios_intermediate_dump.h +++ b/snapshot/ios/thread_snapshot_ios_intermediate_dump.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_SNAPSHOT_IOS_INTERMEDIATE_DUMP_THREAD_SNAPSHOT_IOS_INTERMEDIATEDUMP_H_ #define CRASHPAD_SNAPSHOT_IOS_INTERMEDIATE_DUMP_THREAD_SNAPSHOT_IOS_INTERMEDIATEDUMP_H_ +#include + #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/ios/memory_snapshot_ios_intermediate_dump.h" @@ -49,6 +51,7 @@ class ThreadSnapshotIOSIntermediateDump final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -65,6 +68,7 @@ class ThreadSnapshotIOSIntermediateDump final : public ThreadSnapshot { CPUContext context_; std::vector exception_stack_memory_; MemorySnapshotIOSIntermediateDump stack_; + std::string thread_name_; uint64_t thread_id_; uint64_t thread_specific_data_address_; int suspend_count_; diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 5711f343a4..4b663bbdfe 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -24,6 +24,7 @@ #include #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "build/build_config.h" #include "snapshot/linux/debug_rendezvous.h" #include "util/linux/auxiliary_vector.h" @@ -52,6 +53,7 @@ ProcessReaderLinux::Thread::Thread() : thread_info(), stack_region_address(0), stack_region_size(0), + name(), tid(-1), static_priority(-1), nice_value(-1) {} @@ -64,6 +66,23 @@ bool ProcessReaderLinux::Thread::InitializePtrace( return false; } + // From man proc(5): + // + // /proc/[pid]/comm (since Linux 2.6.33) + // + // Different threads in the same process may have different comm values, + // accessible via /proc/[pid]/task/[tid]/comm. + const std::string path = base::StringPrintf( + "/proc/%d/task/%d/comm", connection->GetProcessID(), tid); + if (connection->ReadFileContents(base::FilePath(path), &name)) { + if (!name.empty() && name.back() == '\n') { + // Remove the final newline character. + name.pop_back(); + } + } else { + // Continue on without the thread name. + } + // TODO(jperaza): Collect scheduling priorities via the broker when they can't // be collected directly. have_priorities = false; diff --git a/snapshot/linux/process_reader_linux.h b/snapshot/linux/process_reader_linux.h index f44e15f5f5..e8cf107028 100644 --- a/snapshot/linux/process_reader_linux.h +++ b/snapshot/linux/process_reader_linux.h @@ -60,6 +60,7 @@ class ProcessReaderLinux { ThreadInfo thread_info; LinuxVMAddress stack_region_address; LinuxVMSize stack_region_size; + std::string name; pid_t tid; int sched_policy; int static_priority; diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index 81b3d6ec67..e4179de1f2 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -43,6 +43,7 @@ #include "test/linux/get_tls.h" #include "test/multiprocess.h" #include "test/scoped_module_handle.h" +#include "test/scoped_set_thread_name.h" #include "test/test_paths.h" #include "util/file/file_io.h" #include "util/file/file_writer.h" @@ -169,7 +170,9 @@ class TestThreadPool { void StartThreads(size_t thread_count, size_t stack_size = 0) { for (size_t thread_index = 0; thread_index < thread_count; ++thread_index) { - threads_.push_back(std::make_unique()); + const std::string thread_name = + base::StringPrintf("ThreadPool-%zu", thread_index); + threads_.push_back(std::make_unique(thread_name)); Thread* thread = threads_.back().get(); pthread_attr_t attr; @@ -211,22 +214,26 @@ class TestThreadPool { } pid_t GetThreadExpectation(size_t thread_index, - ThreadExpectation* expectation) { + ThreadExpectation* expectation, + std::string* thread_name_expectation) { CHECK_LT(thread_index, threads_.size()); const Thread* thread = threads_[thread_index].get(); *expectation = thread->expectation; + *thread_name_expectation = thread->name; return thread->tid; } private: struct Thread { - Thread() + explicit Thread(const std::string& name) : pthread(), expectation(), ready_semaphore(0), exit_semaphore(0), - tid(-1) {} + tid(-1), + name(name) { + } ~Thread() {} pthread_t pthread; @@ -235,10 +242,12 @@ class TestThreadPool { Semaphore ready_semaphore; Semaphore exit_semaphore; pid_t tid; + const std::string name; }; static void* ThreadMain(void* argument) { Thread* thread = static_cast(argument); + const ScopedSetThreadName scoped_set_thread_name(thread->name); CHECK_EQ(setpriority(PRIO_PROCESS, 0, thread->expectation.nice_value), 0) << ErrnoMessage("setpriority"); @@ -260,20 +269,24 @@ class TestThreadPool { }; using ThreadMap = std::map; +using ThreadNameMap = std::map; void ExpectThreads(const ThreadMap& thread_map, + const ThreadNameMap& thread_name_map, const std::vector& threads, PtraceConnection* connection) { ASSERT_EQ(threads.size(), thread_map.size()); + ASSERT_EQ(threads.size(), thread_name_map.size()); MemoryMap memory_map; ASSERT_TRUE(memory_map.Initialize(connection)); for (const auto& thread : threads) { SCOPED_TRACE( - base::StringPrintf("Thread id %d, tls 0x%" PRIx64 + base::StringPrintf("Thread id %d, name %s, tls 0x%" PRIx64 ", stack addr 0x%" PRIx64 ", stack size 0x%" PRIx64, thread.tid, + thread.name.c_str(), thread.thread_info.thread_specific_data_address, thread.stack_region_address, thread.stack_region_size)); @@ -306,6 +319,10 @@ void ExpectThreads(const ThreadMap& thread_map, EXPECT_EQ(thread.sched_policy, iterator->second.sched_policy); EXPECT_EQ(thread.static_priority, iterator->second.static_priority); EXPECT_EQ(thread.nice_value, iterator->second.nice_value); + + const auto& thread_name_iterator = thread_name_map.find(thread.tid); + ASSERT_NE(thread_name_iterator, thread_name_map.end()); + EXPECT_EQ(thread.name, thread_name_iterator->second); } } @@ -322,6 +339,7 @@ class ChildThreadTest : public Multiprocess { private: void MultiprocessParent() override { ThreadMap thread_map; + ThreadNameMap thread_name_map; for (size_t thread_index = 0; thread_index < kThreadCount + 1; ++thread_index) { pid_t tid; @@ -331,6 +349,14 @@ class ChildThreadTest : public Multiprocess { CheckedReadFileExactly( ReadPipeHandle(), &expectation, sizeof(expectation)); thread_map[tid] = expectation; + + std::string::size_type thread_name_length; + CheckedReadFileExactly( + ReadPipeHandle(), &thread_name_length, sizeof(thread_name_length)); + std::string thread_name(thread_name_length, '\0'); + CheckedReadFileExactly( + ReadPipeHandle(), thread_name.data(), thread_name_length); + thread_name_map[tid] = thread_name; } DirectPtraceConnection connection; @@ -340,19 +366,22 @@ class ChildThreadTest : public Multiprocess { ASSERT_TRUE(process_reader.Initialize(&connection)); const std::vector& threads = process_reader.Threads(); - ExpectThreads(thread_map, threads, &connection); + ExpectThreads(thread_map, thread_name_map, threads, &connection); } void MultiprocessChild() override { TestThreadPool thread_pool; thread_pool.StartThreads(kThreadCount, stack_size_); + const std::string current_thread_name = "MultiprocChild"; + const ScopedSetThreadName scoped_set_thread_name(current_thread_name); + TestThreadPool::ThreadExpectation expectation; #if defined(MEMORY_SANITIZER) // memset() + re-initialization is required to zero padding bytes for MSan. memset(&expectation, 0, sizeof(expectation)); #endif // defined(MEMORY_SANITIZER) - expectation = {}; + expectation = {0}; expectation.tls = GetTLS(); expectation.stack_address = reinterpret_cast(&thread_pool); @@ -373,11 +402,28 @@ class ChildThreadTest : public Multiprocess { CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid)); CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation)); + const std::string::size_type current_thread_name_length = + current_thread_name.length(); + CheckedWriteFile(WritePipeHandle(), + ¤t_thread_name_length, + sizeof(current_thread_name_length)); + CheckedWriteFile(WritePipeHandle(), + current_thread_name.data(), + current_thread_name_length); for (size_t thread_index = 0; thread_index < kThreadCount; ++thread_index) { - tid = thread_pool.GetThreadExpectation(thread_index, &expectation); + std::string thread_name_expectation; + tid = thread_pool.GetThreadExpectation( + thread_index, &expectation, &thread_name_expectation); CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid)); CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation)); + const std::string::size_type thread_name_length = + thread_name_expectation.length(); + CheckedWriteFile( + WritePipeHandle(), &thread_name_length, sizeof(thread_name_length)); + CheckedWriteFile(WritePipeHandle(), + thread_name_expectation.data(), + thread_name_length); } CheckedReadFileAtEOF(ReadPipeHandle()); diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc index f279e0adad..04776de6e6 100644 --- a/snapshot/linux/thread_snapshot_linux.cc +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -133,6 +133,7 @@ ThreadSnapshotLinux::ThreadSnapshotLinux() context_(), stack_(), thread_specific_data_address_(0), + thread_name_(), thread_id_(-1), priority_(-1), initialized_() {} @@ -200,6 +201,7 @@ bool ThreadSnapshotLinux::Initialize( thread_specific_data_address_ = thread.thread_info.thread_specific_data_address; + thread_name_ = thread.name; thread_id_ = thread.tid; priority_ = @@ -234,6 +236,11 @@ uint64_t ThreadSnapshotLinux::ThreadID() const { return thread_id_; } +std::string ThreadSnapshotLinux::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_name_; +} + int ThreadSnapshotLinux::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return 0; diff --git a/snapshot/linux/thread_snapshot_linux.h b/snapshot/linux/thread_snapshot_linux.h index 40cd7e7f54..4d1f7a711c 100644 --- a/snapshot/linux/thread_snapshot_linux.h +++ b/snapshot/linux/thread_snapshot_linux.h @@ -57,6 +57,7 @@ class ThreadSnapshotLinux final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -80,6 +81,7 @@ class ThreadSnapshotLinux final : public ThreadSnapshot { CPUContext context_; MemorySnapshotGeneric stack_; LinuxVMAddress thread_specific_data_address_; + std::string thread_name_; pid_t thread_id_; int priority_; InitializationStateDcheck initialized_; diff --git a/snapshot/mac/process_reader_mac.cc b/snapshot/mac/process_reader_mac.cc index 9b2a235627..5f9f8b7b43 100644 --- a/snapshot/mac/process_reader_mac.cc +++ b/snapshot/mac/process_reader_mac.cc @@ -75,6 +75,7 @@ ProcessReaderMac::Thread::Thread() : thread_context(), float_context(), debug_context(), + name(), id(0), stack_region_address(0), stack_region_size(0), @@ -365,6 +366,20 @@ void ProcessReaderMac::InitializeThreads() { thread.thread_specific_data_address = identifier_info.thread_handle; } + thread_extended_info extended_info; + count = THREAD_EXTENDED_INFO_COUNT; + kr = thread_info(thread.port, + THREAD_EXTENDED_INFO, + reinterpret_cast(&extended_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "thread_info(THREAD_EXTENDED_INFO)"; + } else { + thread.name.assign( + extended_info.pth_name, + strnlen(extended_info.pth_name, sizeof(extended_info.pth_name))); + } + thread_precedence_policy precedence; count = THREAD_PRECEDENCE_POLICY_COUNT; boolean_t get_default = FALSE; diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h index 85cfe7c988..4f7792f895 100644 --- a/snapshot/mac/process_reader_mac.h +++ b/snapshot/mac/process_reader_mac.h @@ -75,6 +75,7 @@ class ProcessReaderMac { ThreadContext thread_context; FloatContext float_context; DebugContext debug_context; + std::string name; uint64_t id; mach_vm_address_t stack_region_address; mach_vm_size_t stack_region_size; diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 8868950845..aef4a7a3d5 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -42,6 +42,7 @@ #include "test/mac/dyld.h" #include "test/mac/mach_errors.h" #include "test/mac/mach_multiprocess.h" +#include "test/scoped_set_thread_name.h" #include "util/file/file_io.h" #include "util/mac/mac_util.h" #include "util/mach/mach_extensions.h" @@ -139,6 +140,9 @@ uint64_t PthreadToThreadID(pthread_t pthread) { } TEST(ProcessReaderMac, SelfOneThread) { + const ScopedSetThreadName scoped_set_thread_name( + "ProcessReaderMac/SelfOneThread"); + ProcessReaderMac process_reader; ASSERT_TRUE(process_reader.Initialize(mach_task_self())); @@ -151,6 +155,7 @@ TEST(ProcessReaderMac, SelfOneThread) { ASSERT_GE(threads.size(), 1u); EXPECT_EQ(threads[0].id, PthreadToThreadID(pthread_self())); + EXPECT_EQ(threads[0].name, "ProcessReaderMac/SelfOneThread"); thread_t thread_self = MachThreadSelf(); EXPECT_EQ(threads[0].port, thread_self); @@ -163,9 +168,11 @@ class TestThreadPool { struct ThreadExpectation { mach_vm_address_t stack_address; int suspend_count; + std::string thread_name; }; - TestThreadPool() : thread_infos_() {} + TestThreadPool(const std::string& thread_name_prefix) + : thread_infos_(), thread_name_prefix_(thread_name_prefix) {} TestThreadPool(const TestThreadPool&) = delete; TestThreadPool& operator=(const TestThreadPool&) = delete; @@ -199,7 +206,10 @@ class TestThreadPool { ASSERT_TRUE(thread_infos_.empty()); for (size_t thread_index = 0; thread_index < thread_count; ++thread_index) { - thread_infos_.push_back(std::make_unique()); + std::string thread_name = base::StringPrintf( + "%s-%zu", thread_name_prefix_.c_str(), thread_index); + thread_infos_.push_back( + std::make_unique(std::move(thread_name))); ThreadInfo* thread_info = thread_infos_.back().get(); int rv = pthread_create( @@ -235,18 +245,20 @@ class TestThreadPool { const auto& thread_info = thread_infos_[thread_index]; expectation->stack_address = thread_info->stack_address; expectation->suspend_count = thread_info->suspend_count; + expectation->thread_name = thread_info->thread_name; return PthreadToThreadID(thread_info->pthread); } private: struct ThreadInfo { - ThreadInfo() + ThreadInfo(const std::string& thread_name) : pthread(nullptr), stack_address(0), ready_semaphore(0), exit_semaphore(0), - suspend_count(0) {} + suspend_count(0), + thread_name(thread_name) {} ~ThreadInfo() {} @@ -270,10 +282,14 @@ class TestThreadPool { // The thread’s suspend count. int suspend_count; + + // The thread's name. + const std::string thread_name; }; static void* ThreadMain(void* argument) { ThreadInfo* thread_info = static_cast(argument); + const ScopedSetThreadName scoped_set_thread_name(thread_info->thread_name); thread_info->stack_address = FromPointerCast(&thread_info); @@ -293,6 +309,9 @@ class TestThreadPool { // This is a vector of pointers because the address of a ThreadInfo object is // passed to each thread’s ThreadMain(), so they cannot move around in memory. std::vector> thread_infos_; + + // Prefix to use for each thread's name, suffixed with "-$threadindex". + const std::string thread_name_prefix_; }; using ThreadMap = std::map; @@ -328,6 +347,7 @@ void ExpectSeveralThreads(ThreadMap* thread_map, EXPECT_LT(iterator->second.stack_address, thread_stack_region_end); EXPECT_EQ(thread.suspend_count, iterator->second.suspend_count); + EXPECT_EQ(thread.name, iterator->second.thread_name); // Remove the thread from the expectation map since it’s already been // found. This makes it easy to check for duplicate thread IDs, and makes @@ -374,7 +394,7 @@ TEST(ProcessReaderMac, SelfSeveralThreads) { ProcessReaderMac process_reader; ASSERT_TRUE(process_reader.Initialize(mach_task_self())); - TestThreadPool thread_pool; + TestThreadPool thread_pool("SelfSeveralThreads"); constexpr size_t kChildThreads = 16; ASSERT_NO_FATAL_FAILURE(thread_pool.StartThreads(kChildThreads)); @@ -392,6 +412,8 @@ TEST(ProcessReaderMac, SelfSeveralThreads) { // There can’t be any duplicate thread IDs. EXPECT_EQ(thread_map.count(thread_id), 0u); + expectation.thread_name = + base::StringPrintf("SelfSeveralThreads-%zu", thread_index); thread_map[thread_id] = expectation; } @@ -431,8 +453,11 @@ uint64_t GetThreadID() { class ProcessReaderThreadedChild final : public MachMultiprocess { public: - explicit ProcessReaderThreadedChild(size_t thread_count) - : MachMultiprocess(), thread_count_(thread_count) {} + explicit ProcessReaderThreadedChild(const std::string thread_name_prefix, + size_t thread_count) + : MachMultiprocess(), + thread_name_prefix_(thread_name_prefix), + thread_count_(thread_count) {} ProcessReaderThreadedChild(const ProcessReaderThreadedChild&) = delete; ProcessReaderThreadedChild& operator=(const ProcessReaderThreadedChild&) = @@ -463,6 +488,15 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedReadFileExactly(read_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); + std::string::size_type expected_thread_name_length; + CheckedReadFileExactly(read_handle, + &expected_thread_name_length, + sizeof(expected_thread_name_length)); + std::string expected_thread_name(expected_thread_name_length, '\0'); + CheckedReadFileExactly(read_handle, + expected_thread_name.data(), + expected_thread_name_length); + expectation.thread_name = expected_thread_name; // There can’t be any duplicate thread IDs. EXPECT_EQ(thread_map.count(thread_id), 0u); @@ -479,9 +513,13 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { } void MachMultiprocessChild() override { - TestThreadPool thread_pool; + TestThreadPool thread_pool(thread_name_prefix_); ASSERT_NO_FATAL_FAILURE(thread_pool.StartThreads(thread_count_)); + const std::string current_thread_name(base::StringPrintf( + "%s-MachMultiprocessChild", thread_name_prefix_.c_str())); + const ScopedSetThreadName scoped_set_thread_name(current_thread_name); + FileHandle write_handle = WritePipeHandle(); // This thread isn’t part of the thread pool, but the parent will be able @@ -500,6 +538,13 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedWriteFile(write_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); + const std::string::size_type current_thread_name_length = + current_thread_name.length(); + CheckedWriteFile(write_handle, + ¤t_thread_name_length, + sizeof(current_thread_name_length)); + CheckedWriteFile( + write_handle, current_thread_name.data(), current_thread_name_length); // Write an entry for everything in the thread pool. for (size_t thread_index = 0; thread_index < thread_count_; @@ -513,6 +558,16 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedWriteFile(write_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); + const std::string thread_pool_thread_name = base::StringPrintf( + "%s-%zu", thread_name_prefix_.c_str(), thread_index); + const std::string::size_type thread_pool_thread_name_length = + thread_pool_thread_name.length(); + CheckedWriteFile(write_handle, + &thread_pool_thread_name_length, + sizeof(thread_pool_thread_name_length)); + CheckedWriteFile(write_handle, + thread_pool_thread_name.data(), + thread_pool_thread_name_length); } // Wait for the parent to signal that it’s OK to exit by closing its end of @@ -520,19 +575,22 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedReadFileAtEOF(ReadPipeHandle()); } + const std::string thread_name_prefix_; size_t thread_count_; }; TEST(ProcessReaderMac, ChildOneThread) { // The main thread plus zero child threads equals one thread. constexpr size_t kChildThreads = 0; - ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); + ProcessReaderThreadedChild process_reader_threaded_child("ChildOneThread", + kChildThreads); process_reader_threaded_child.Run(); } TEST(ProcessReaderMac, ChildSeveralThreads) { constexpr size_t kChildThreads = 64; - ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); + ProcessReaderThreadedChild process_reader_threaded_child( + "ChildSeveralThreads", kChildThreads); process_reader_threaded_child.Run(); } diff --git a/snapshot/mac/thread_snapshot_mac.cc b/snapshot/mac/thread_snapshot_mac.cc index d261f194ad..485ffc21a9 100644 --- a/snapshot/mac/thread_snapshot_mac.cc +++ b/snapshot/mac/thread_snapshot_mac.cc @@ -26,13 +26,13 @@ ThreadSnapshotMac::ThreadSnapshotMac() context_union_(), context_(), stack_(), + thread_name_(), thread_id_(0), thread_specific_data_address_(0), thread_(MACH_PORT_NULL), suspend_count_(0), priority_(0), - initialized_() { -} + initialized_() {} ThreadSnapshotMac::~ThreadSnapshotMac() { } @@ -44,6 +44,7 @@ bool ThreadSnapshotMac::Initialize( thread_ = process_reader_thread.port; thread_id_ = process_reader_thread.id; + thread_name_ = process_reader_thread.name; suspend_count_ = process_reader_thread.suspend_count; priority_ = process_reader_thread.priority; thread_specific_data_address_ = @@ -108,6 +109,11 @@ uint64_t ThreadSnapshotMac::ThreadID() const { return thread_id_; } +std::string ThreadSnapshotMac::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_name_; +} + int ThreadSnapshotMac::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return suspend_count_; diff --git a/snapshot/mac/thread_snapshot_mac.h b/snapshot/mac/thread_snapshot_mac.h index 4d9cb3167f..ebdb3ae352 100644 --- a/snapshot/mac/thread_snapshot_mac.h +++ b/snapshot/mac/thread_snapshot_mac.h @@ -18,6 +18,8 @@ #include #include +#include + #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/mac/process_reader_mac.h" @@ -60,6 +62,7 @@ class ThreadSnapshotMac final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -78,6 +81,7 @@ class ThreadSnapshotMac final : public ThreadSnapshot { } context_union_; CPUContext context_; MemorySnapshotGeneric stack_; + std::string thread_name_; uint64_t thread_id_; uint64_t thread_specific_data_address_; thread_t thread_; diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 8c870ee005..28942447dc 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -23,6 +23,7 @@ #include "minidump/minidump_extensions.h" #include "snapshot/memory_map_region_snapshot.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" +#include "snapshot/minidump/minidump_string_reader.h" #include "util/file/file_io.h" namespace crashpad { @@ -576,12 +577,16 @@ bool ProcessSnapshotMinidump::InitializeThreads() { return false; } + if (!InitializeThreadNames()) { + return false; + } + for (uint32_t thread_index = 0; thread_index < thread_count; ++thread_index) { const RVA thread_rva = stream_it->second->Rva + sizeof(thread_count) + thread_index * sizeof(MINIDUMP_THREAD); auto thread = std::make_unique(); - if (!thread->Initialize(file_reader_, thread_rva, arch_)) { + if (!thread->Initialize(file_reader_, thread_rva, arch_, thread_names_)) { return false; } @@ -591,6 +596,59 @@ bool ProcessSnapshotMinidump::InitializeThreads() { return true; } +bool ProcessSnapshotMinidump::InitializeThreadNames() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadNameList); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_THREAD_NAME_LIST)) { + LOG(ERROR) << "thread_name_list size mismatch"; + return false; + } + + if (!file_reader_->SeekSet(stream_it->second->Rva)) { + return false; + } + + uint32_t thread_name_count; + if (!file_reader_->ReadExactly(&thread_name_count, + sizeof(thread_name_count))) { + return false; + } + + if (sizeof(MINIDUMP_THREAD_NAME_LIST) + + thread_name_count * sizeof(MINIDUMP_THREAD_NAME) != + stream_it->second->DataSize) { + LOG(ERROR) << "thread_name_list size mismatch"; + return false; + } + + for (uint32_t thread_name_index = 0; thread_name_index < thread_name_count; + ++thread_name_index) { + const RVA thread_name_rva = + stream_it->second->Rva + sizeof(thread_name_count) + + thread_name_index * sizeof(MINIDUMP_THREAD_NAME); + if (!file_reader_->SeekSet(thread_name_rva)) { + return false; + } + MINIDUMP_THREAD_NAME minidump_thread_name; + if (!file_reader_->ReadExactly(&minidump_thread_name, + sizeof(minidump_thread_name))) { + return false; + } + std::string name; + if (!internal::ReadMinidumpUTF16String( + file_reader_, minidump_thread_name.RvaOfThreadName, &name)) { + return false; + } + + thread_names_.emplace(minidump_thread_name.ThreadId, std::move(name)); + } + + return true; +} + bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeSystemInfo); if (stream_it == stream_map_.end()) { diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 18fbc7c367..351fc4e1f0 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -112,6 +112,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeThreads(); + // Initializes data carried in a MINIDUMP_THREAD_NAME_LIST stream on behalf of + // Initialize(). + bool InitializeThreadNames(); + // Initializes data carried in a MINIDUMP_MEMORY_INFO_LIST stream on behalf of // Initialize(). bool InitializeMemoryInfo(); @@ -147,6 +151,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::map stream_map_; std::vector> modules_; std::vector> threads_; + std::map thread_names_; std::vector unloaded_modules_; std::vector> mem_regions_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index ded561bf1c..902d699ee8 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -728,6 +728,104 @@ TEST(ProcessSnapshotMinidump, Threads) { } } +TEST(ProcessSnapshotMinidump, ThreadsWithNames) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + constexpr uint32_t kMinidumpThreadCount = 4; + constexpr uint32_t kBaseThreadId = 42; + + const std::string thread_names[kMinidumpThreadCount] = { + "ariadne", + "theseus", + "pasiphae", + "minos", + }; + + RVA64 thread_name_rva64s[kMinidumpThreadCount]; + for (uint32_t i = 0; i < kMinidumpThreadCount; i++) { + thread_name_rva64s[i] = static_cast(string_file.SeekGet()); + auto name16 = base::UTF8ToUTF16(thread_names[i]); + uint32_t size = + base::checked_cast(sizeof(name16[0]) * name16.size()); + EXPECT_TRUE(string_file.Write(&size, sizeof(size))); + EXPECT_TRUE(string_file.Write(&name16[0], size)); + } + + MINIDUMP_DIRECTORY minidump_thread_list_directory = {}; + minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList; + minidump_thread_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_LIST) + + kMinidumpThreadCount * sizeof(MINIDUMP_THREAD); + minidump_thread_list_directory.Location.Rva = + static_cast(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_LIST. + EXPECT_TRUE( + string_file.Write(&kMinidumpThreadCount, sizeof(kMinidumpThreadCount))); + for (uint32_t minidump_thread_index = 0; + minidump_thread_index < kMinidumpThreadCount; + ++minidump_thread_index) { + MINIDUMP_THREAD minidump_thread = {}; + minidump_thread.ThreadId = kBaseThreadId + minidump_thread_index; + EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread))); + } + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_list_directory))); + + MINIDUMP_DIRECTORY minidump_thread_name_list_directory = {}; + minidump_thread_name_list_directory.StreamType = + kMinidumpStreamTypeThreadNameList; + minidump_thread_name_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_NAME_LIST) + + kMinidumpThreadCount * sizeof(MINIDUMP_THREAD_NAME); + minidump_thread_name_list_directory.Location.Rva = + static_cast(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_NAME_LIST. + EXPECT_TRUE( + string_file.Write(&kMinidumpThreadCount, sizeof(kMinidumpThreadCount))); + for (uint32_t minidump_thread_index = 0; + minidump_thread_index < kMinidumpThreadCount; + ++minidump_thread_index) { + MINIDUMP_THREAD_NAME minidump_thread_name = {0}; + minidump_thread_name.ThreadId = kBaseThreadId + minidump_thread_index; + minidump_thread_name.RvaOfThreadName = + thread_name_rva64s[minidump_thread_index]; + EXPECT_TRUE( + string_file.Write(&minidump_thread_name, sizeof(minidump_thread_name))); + } + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_list_directory))); + ASSERT_TRUE(string_file.Write(&minidump_thread_name_list_directory, + sizeof(minidump_thread_name_list_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 2; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + std::vector threads = process_snapshot.Threads(); + ASSERT_EQ(threads.size(), kMinidumpThreadCount); + + size_t idx = 0; + for (const auto& thread : threads) { + EXPECT_EQ(thread->ThreadID(), kBaseThreadId + idx); + EXPECT_EQ(thread->ThreadName(), thread_names[idx]); + idx++; + } +} + TEST(ProcessSnapshotMinidump, System) { const char* cpu_info = "GenuineIntel"; const uint32_t* cpu_info_bytes = reinterpret_cast(cpu_info); diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index f8f3673f4c..26aabd7039 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -26,15 +26,18 @@ namespace internal { ThreadSnapshotMinidump::ThreadSnapshotMinidump() : ThreadSnapshot(), minidump_thread_(), + thread_name_(), context_(), stack_(), initialized_() {} ThreadSnapshotMinidump::~ThreadSnapshotMinidump() {} -bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, - RVA minidump_thread_rva, - CPUArchitecture arch) { +bool ThreadSnapshotMinidump::Initialize( + FileReaderInterface* file_reader, + RVA minidump_thread_rva, + CPUArchitecture arch, + const std::map& thread_names) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); std::vector minidump_context; @@ -67,6 +70,10 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, if (!stack_.Initialize(file_reader, stack_info_location)) { return false; } + const auto thread_name_iter = thread_names.find(minidump_thread_.ThreadId); + if (thread_name_iter != thread_names.end()) { + thread_name_ = thread_name_iter->second; + } INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -77,6 +84,11 @@ uint64_t ThreadSnapshotMinidump::ThreadID() const { return minidump_thread_.ThreadId; } +std::string ThreadSnapshotMinidump::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_name_; +} + int ThreadSnapshotMinidump::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return minidump_thread_.SuspendCount; diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h index 7efb18d71c..b0ef424aac 100644 --- a/snapshot/minidump/thread_snapshot_minidump.h +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -17,6 +17,8 @@ #include +#include + #include "minidump/minidump_extensions.h" #include "snapshot/cpu_context.h" #include "snapshot/minidump/memory_snapshot_minidump.h" @@ -46,16 +48,20 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { //! the thread’s MINIDUMP_THREAD structure is located. //! \param[in] arch The architecture of the system this thread is running on. //! Used to decode CPU Context. + //! \param[in] thread_names Map from thread ID to thread name previously read + //! from the minidump's MINIDUMP_THREAD_NAME_LIST. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva, - CPUArchitecture arch); + CPUArchitecture arch, + const std::map& thread_names); const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -71,6 +77,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { bool InitializeContext(const std::vector& minidump_context); MINIDUMP_THREAD minidump_thread_; + std::string thread_name_; MinidumpContextConverter context_; MemorySnapshotMinidump stack_; InitializationStateDcheck initialized_; diff --git a/snapshot/sanitized/thread_snapshot_sanitized.cc b/snapshot/sanitized/thread_snapshot_sanitized.cc index 186776eae0..4a1fb72ab1 100644 --- a/snapshot/sanitized/thread_snapshot_sanitized.cc +++ b/snapshot/sanitized/thread_snapshot_sanitized.cc @@ -39,6 +39,10 @@ uint64_t ThreadSnapshotSanitized::ThreadID() const { return snapshot_->ThreadID(); } +std::string ThreadSnapshotSanitized::ThreadName() const { + return snapshot_->ThreadName(); +} + int ThreadSnapshotSanitized::SuspendCount() const { return snapshot_->SuspendCount(); } diff --git a/snapshot/sanitized/thread_snapshot_sanitized.h b/snapshot/sanitized/thread_snapshot_sanitized.h index dca0a0e917..b520579772 100644 --- a/snapshot/sanitized/thread_snapshot_sanitized.h +++ b/snapshot/sanitized/thread_snapshot_sanitized.h @@ -17,6 +17,8 @@ #include "snapshot/thread_snapshot.h" +#include + #include "snapshot/sanitized/memory_snapshot_sanitized.h" #include "util/misc/range_set.h" @@ -44,6 +46,7 @@ class ThreadSnapshotSanitized final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; diff --git a/snapshot/test/test_thread_snapshot.cc b/snapshot/test/test_thread_snapshot.cc index ed6d9fdab2..3e73ecdaac 100644 --- a/snapshot/test/test_thread_snapshot.cc +++ b/snapshot/test/test_thread_snapshot.cc @@ -43,6 +43,10 @@ uint64_t TestThreadSnapshot::ThreadID() const { return thread_id_; } +std::string TestThreadSnapshot::ThreadName() const { + return thread_name_; +} + int TestThreadSnapshot::SuspendCount() const { return suspend_count_; } diff --git a/snapshot/test/test_thread_snapshot.h b/snapshot/test/test_thread_snapshot.h index f865bdfea7..a1cef21be3 100644 --- a/snapshot/test/test_thread_snapshot.h +++ b/snapshot/test/test_thread_snapshot.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -63,6 +64,9 @@ class TestThreadSnapshot final : public ThreadSnapshot { } void SetThreadID(uint64_t thread_id) { thread_id_ = thread_id; } + void SetThreadName(const std::string& thread_name) { + thread_name_ = thread_name; + } void SetSuspendCount(int suspend_count) { suspend_count_ = suspend_count; } void SetPriority(int priority) { priority_ = priority; } void SetThreadSpecificDataAddress(uint64_t thread_specific_data_address) { @@ -83,6 +87,7 @@ class TestThreadSnapshot final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; @@ -96,6 +101,7 @@ class TestThreadSnapshot final : public ThreadSnapshot { CPUContext context_; std::unique_ptr stack_; uint64_t thread_id_; + std::string thread_name_; int suspend_count_; int priority_; uint64_t thread_specific_data_address_; diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h index 4d732578e5..ade3ee6c83 100644 --- a/snapshot/thread_snapshot.h +++ b/snapshot/thread_snapshot.h @@ -17,6 +17,7 @@ #include +#include #include namespace crashpad { @@ -51,6 +52,9 @@ class ThreadSnapshot { //! unique system-wide. virtual uint64_t ThreadID() const = 0; + //! \brief Returns the thread's name. + virtual std::string ThreadName() const = 0; + //! \brief Returns the thread’s suspend count. //! //! A suspend count of `0` denotes a schedulable (not suspended) thread. diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index 23073803b9..45a932c0ea 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -21,13 +21,16 @@ #include "base/notreached.h" #include "base/numerics/safe_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "snapshot/win/cpu_context_win.h" #include "util/misc/capture_context.h" #include "util/misc/time.h" +#include "util/win/get_function.h" #include "util/win/nt_internals.h" #include "util/win/ntstatus_logging.h" #include "util/win/process_structs.h" #include "util/win/scoped_handle.h" +#include "util/win/scoped_local_alloc.h" namespace crashpad { @@ -232,12 +235,9 @@ bool ProcessReaderWin::ThreadContext::InitializeWow64(HANDLE thread_handle) { bool ProcessReaderWin::ThreadContext::InitializeXState( HANDLE thread_handle, ULONG64 XStateCompactionMask) { - static auto initialize_context_2 = []() { - // InitializeContext2 needs Windows 10 build 20348. - HINSTANCE kernel32 = GetModuleHandle(L"Kernel32.dll"); - return reinterpret_cast( - GetProcAddress(kernel32, "InitializeContext2")); - }(); + // InitializeContext2 needs Windows 10 build 20348. + static const auto initialize_context_2 = + GET_FUNCTION(L"kernel32.dll", ::InitializeContext2); if (!initialize_context_2) return false; // We want CET_U xstate to get the ssp, only possible when supported. @@ -276,6 +276,7 @@ bool ProcessReaderWin::ThreadContext::InitializeXState( ProcessReaderWin::Thread::Thread() : context(), + name(), id(0), teb_address(0), teb_size(0), @@ -460,6 +461,21 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { thread.stack_region_size = base - limit; } } + // On Windows 10 build 1607 and later, read the thread name. + static const auto get_thread_description = + GET_FUNCTION(L"kernel32.dll", ::GetThreadDescription); + if (get_thread_description) { + wchar_t* thread_description; + HRESULT hr = + get_thread_description(thread_handle.get(), &thread_description); + if (SUCCEEDED(hr)) { + ScopedLocalAlloc thread_description_owner(thread_description); + thread.name = base::WideToUTF8(thread_description); + } else { + LOG(WARNING) << "GetThreadDescription: " + << logging::SystemErrorCodeToString(hr); + } + } threads_.push_back(thread); } } diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index 5987c005c4..90ff1cb761 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "build/build_config.h" @@ -77,6 +78,7 @@ class ProcessReaderWin { ~Thread() {} ThreadContext context; + std::string name; uint64_t id; WinVMAddress teb_address; WinVMSize teb_size; diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 15a6e2b728..6cfd8a4f45 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -17,9 +17,17 @@ #include #include +#include +#include #include +#include +#include +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" +#include "test/scoped_set_thread_name.h" #include "test/win/win_multiprocess.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -31,6 +39,8 @@ namespace crashpad { namespace test { namespace { +using ::testing::IsSupersetOf; + TEST(ProcessReaderWin, SelfBasic) { ProcessReaderWin process_reader; ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(), @@ -98,6 +108,7 @@ TEST(ProcessReaderWin, ChildBasic) { } TEST(ProcessReaderWin, SelfOneThread) { + const ScopedSetThreadName scoped_set_thread_name("SelfBasic"); ProcessReaderWin process_reader; ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(), ProcessSuspensionState::kRunning)); @@ -111,6 +122,7 @@ TEST(ProcessReaderWin, SelfOneThread) { ASSERT_GE(threads.size(), 1u); EXPECT_EQ(threads[0].id, GetCurrentThreadId()); + EXPECT_EQ(threads[0].name, "SelfBasic"); EXPECT_NE(ProgramCounterFromCONTEXT(threads[0].context.context()), nullptr); EXPECT_EQ(threads[0].suspend_count, 0u); @@ -132,18 +144,21 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { class SleepingThread : public Thread { public: - SleepingThread() : done_(nullptr) {} + SleepingThread(const std::string& thread_name) + : done_(nullptr), thread_name_(thread_name) {} void SetHandle(Semaphore* done) { done_= done; } void ThreadMain() override { + const ScopedSetThreadName scoped_set_thread_name(thread_name_); done_->Wait(); } private: Semaphore* done_; + const std::string thread_name_; }; void WinMultiprocessParent() override { @@ -158,8 +173,28 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { const auto& threads = process_reader.Threads(); ASSERT_GE(threads.size(), kCreatedThreads + 1); - for (const auto& thread : threads) + EXPECT_EQ(threads[0].name, "WinMultiprocessChild-Main"); + + const std::set expected_thread_names = { + "WinMultiprocessChild-1", + "WinMultiprocessChild-2", + "WinMultiprocessChild-3", + }; + // Windows can create threads besides the ones created in + // WinMultiprocessChild(), so keep track of the (non-main) thread names + // and make sure all the expected names are present. + std::set thread_names; + for (size_t i = 1; i < threads.size(); i++) { + if (!threads[i].name.empty()) { + thread_names.emplace(threads[i].name); + } + } + + EXPECT_THAT(thread_names, IsSupersetOf(expected_thread_names)); + + for (const auto& thread : threads) { EXPECT_EQ(thread.suspend_count, 0u); + } } { @@ -173,15 +208,23 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { // suspended. const auto& threads = process_reader.Threads(); ASSERT_GE(threads.size(), kCreatedThreads + 1); - for (const auto& thread : threads) + for (const auto& thread : threads) { EXPECT_EQ(thread.suspend_count, 0u); + } } } void WinMultiprocessChild() override { + const ScopedSetThreadName scoped_set_thread_name( + "WinMultiprocessChild-Main"); + // Create three dummy threads so we can confirm we read successfully read // more than just the main thread. - SleepingThread threads[kCreatedThreads]; + std::array threads = { + "WinMultiprocessChild-1", + "WinMultiprocessChild-2", + "WinMultiprocessChild-3", + }; Semaphore done(0); for (auto& thread : threads) thread.SetHandle(&done); diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index f1a20b5d7d..844986db59 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -45,8 +45,7 @@ ProcessSnapshotWin::ProcessSnapshotWin() annotations_simple_map_(), snapshot_time_(), options_(), - initialized_() { -} + initialized_() {} ProcessSnapshotWin::~ProcessSnapshotWin() { } diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index 2c5569f8f1..222b2ab443 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -165,6 +165,11 @@ uint64_t ThreadSnapshotWin::ThreadID() const { return thread_.id; } +std::string ThreadSnapshotWin::ThreadName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_.name; +} + int ThreadSnapshotWin::SuspendCount() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return thread_.suspend_count; diff --git a/snapshot/win/thread_snapshot_win.h b/snapshot/win/thread_snapshot_win.h index b9fafaa23c..af18a14ba8 100644 --- a/snapshot/win/thread_snapshot_win.h +++ b/snapshot/win/thread_snapshot_win.h @@ -68,6 +68,7 @@ class ThreadSnapshotWin final : public ThreadSnapshot { const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; uint64_t ThreadID() const override; + std::string ThreadName() const override; int SuspendCount() const override; int Priority() const override; uint64_t ThreadSpecificDataAddress() const override; diff --git a/test/BUILD.gn b/test/BUILD.gn index dfc84d162f..28b4e8d14f 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -37,6 +37,7 @@ static_library("test") { "scoped_guarded_page.h", "scoped_module_handle.cc", "scoped_module_handle.h", + "scoped_set_thread_name.h", "scoped_temp_dir.cc", "scoped_temp_dir.h", "test_paths.cc", @@ -57,6 +58,14 @@ static_library("test") { } } + # TODO(crbug.com/812974): Remove !crashpad_is_fuchsia when Fuchsia is no + # longer treated as a posix platform. + if (crashpad_is_posix && !crashpad_is_fuchsia) { + sources += [ + "scoped_set_thread_name_posix.cc", + ] + } + if (crashpad_is_mac || crashpad_is_ios) { sources += [ "mac/mach_errors.cc", @@ -96,6 +105,7 @@ static_library("test") { sources += [ "multiprocess_exec_win.cc", "scoped_guarded_page_win.cc", + "scoped_set_thread_name_win.cc", "scoped_temp_dir_win.cc", "win/child_launcher.cc", "win/child_launcher.h", @@ -109,7 +119,10 @@ static_library("test") { } if (crashpad_is_fuchsia) { - sources += [ "multiprocess_exec_fuchsia.cc" ] + sources += [ + "multiprocess_exec_fuchsia.cc", + "scoped_set_thread_name_fuchsia.cc", + ] } public_configs = [ "..:crashpad_config" ] diff --git a/test/scoped_set_thread_name.h b/test/scoped_set_thread_name.h new file mode 100644 index 0000000000..69998c03b9 --- /dev/null +++ b/test/scoped_set_thread_name.h @@ -0,0 +1,46 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_TEST_SCOPED_SET_THREAD_NAME_H_ +#define CRASHPAD_TEST_SCOPED_SET_THREAD_NAME_H_ + +#include + +#include "build/build_config.h" + +namespace crashpad { +namespace test { + +//! Sets the name of the current thread for the lifetime of this object. +class ScopedSetThreadName final { + public: + explicit ScopedSetThreadName(const std::string& new_thread_name); + + ScopedSetThreadName(const ScopedSetThreadName&) = delete; + ScopedSetThreadName& operator=(const ScopedSetThreadName&) = delete; + + ~ScopedSetThreadName(); + + private: +#if BUILDFLAG(IS_WIN) + const std::wstring original_name_; +#else + const std::string original_name_; +#endif +}; + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_TEST_SCOPED_SET_THREAD_NAME_H_ diff --git a/test/scoped_set_thread_name_fuchsia.cc b/test/scoped_set_thread_name_fuchsia.cc new file mode 100644 index 0000000000..7b672d1513 --- /dev/null +++ b/test/scoped_set_thread_name_fuchsia.cc @@ -0,0 +1,61 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "test/scoped_set_thread_name.h" + +#include + +#include +#include +#include + +#include "base/check_op.h" +#include "base/fuchsia/fuchsia_logging.h" + +namespace crashpad { +namespace test { + +namespace { + +std::string GetCurrentThreadName() { + std::string result(ZX_MAX_NAME_LEN, '\0'); + const zx_status_t status = zx::thread::self()->get_property( + ZX_PROP_NAME, result.data(), result.length()); + ZX_CHECK(status == ZX_OK, status) << "get_property(ZX_PROP_NAME)"; + const auto result_nul_idx = result.find('\0'); + CHECK_NE(result_nul_idx, std::string::npos) + << "get_property() did not NUL terminate"; + result.resize(result_nul_idx); + return result; +} + +} // namespace + +ScopedSetThreadName::ScopedSetThreadName(const std::string& new_thread_name) + : original_name_(GetCurrentThreadName()) { + // Fuchsia silently truncates the thread name if it's too long. + CHECK_LT(new_thread_name.length(), ZX_MAX_NAME_LEN); + const zx_status_t status = zx::thread::self()->set_property( + ZX_PROP_NAME, new_thread_name.c_str(), new_thread_name.length()); + ZX_CHECK(status == ZX_OK, status) << "set_property(ZX_PROP_NAME)"; +} + +ScopedSetThreadName::~ScopedSetThreadName() { + const zx_status_t status = zx::thread::self()->set_property( + ZX_PROP_NAME, original_name_.c_str(), original_name_.length()); + ZX_CHECK(status == ZX_OK, status) << "set_property(ZX_PROP_NAME)"; +} + +} // namespace test +} // namespace crashpad diff --git a/test/scoped_set_thread_name_posix.cc b/test/scoped_set_thread_name_posix.cc new file mode 100644 index 0000000000..66146c066a --- /dev/null +++ b/test/scoped_set_thread_name_posix.cc @@ -0,0 +1,80 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "test/scoped_set_thread_name.h" + +#include +#include + +#include + +#include "base/check.h" +#include "build/build_config.h" + +#if BUILDFLAG(IS_APPLE) +#include +#endif + +namespace crashpad { +namespace test { + +namespace { + +#if BUILDFLAG(IS_LINUX) +// The kernel headers define this in linux/sched.h as TASK_COMM_LEN, but the +// userspace copy of that header does not define it. +constexpr size_t kPthreadNameMaxLen = 16; +#elif BUILDFLAG(IS_APPLE) +constexpr size_t kPthreadNameMaxLen = MAXTHREADNAMESIZE; +#else +#error Port to your platform +#endif + +void SetCurrentThreadName(const std::string& thread_name) { +#if BUILDFLAG(IS_LINUX) + PCHECK((errno = pthread_setname_np(pthread_self(), thread_name.c_str())) == 0) + << "pthread_setname_np"; +#elif BUILDFLAG(IS_APPLE) + // Apple's pthread_setname_np() sets errno instead of returning it. + PCHECK(pthread_setname_np(thread_name.c_str()) == 0) << "pthread_setname_np"; +#else +#error Port to your platform +#endif +} + +std::string GetCurrentThreadName() { + std::string result(kPthreadNameMaxLen, '\0'); + PCHECK((errno = pthread_getname_np( + pthread_self(), result.data(), result.length())) == 0) + << "pthread_getname_np"; + const auto result_nul_idx = result.find('\0'); + CHECK(result_nul_idx != std::string::npos) + << "pthread_getname_np did not NUL terminate"; + result.resize(result_nul_idx); + return result; +} + +} // namespace + +ScopedSetThreadName::ScopedSetThreadName(const std::string& new_thread_name) + : original_name_(GetCurrentThreadName()) { + SetCurrentThreadName(new_thread_name); +} + +ScopedSetThreadName::~ScopedSetThreadName() { + SetCurrentThreadName(original_name_); +} + +} // namespace test +} // namespace crashpad diff --git a/test/scoped_set_thread_name_win.cc b/test/scoped_set_thread_name_win.cc new file mode 100644 index 0000000000..482d3c12e5 --- /dev/null +++ b/test/scoped_set_thread_name_win.cc @@ -0,0 +1,56 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "test/scoped_set_thread_name.h" + +#include + +#include "base/check.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "util/win/scoped_local_alloc.h" + +namespace crashpad { +namespace test { + +namespace { + +std::wstring GetCurrentThreadName() { + wchar_t* thread_description; + HRESULT hr = GetThreadDescription(GetCurrentThread(), &thread_description); + CHECK(SUCCEEDED(hr)) << "GetThreadDescription: " + << logging::SystemErrorCodeToString(hr); + ScopedLocalAlloc thread_description_owner(thread_description); + return std::wstring(thread_description); +} + +} // namespace + +ScopedSetThreadName::ScopedSetThreadName(const std::string& new_thread_name) + : original_name_(GetCurrentThreadName()) { + const std::wstring wnew_thread_name = base::UTF8ToWide(new_thread_name); + HRESULT hr = + SetThreadDescription(GetCurrentThread(), wnew_thread_name.c_str()); + CHECK(SUCCEEDED(hr)) << "SetThreadDescription: " + << logging::SystemErrorCodeToString(hr); +} + +ScopedSetThreadName::~ScopedSetThreadName() { + HRESULT hr = SetThreadDescription(GetCurrentThread(), original_name_.c_str()); + CHECK(SUCCEEDED(hr)) << "SetThreadDescription: " + << logging::SystemErrorCodeToString(hr); +} + +} // namespace test +} // namespace crashpad diff --git a/util/ios/ios_intermediate_dump_format.h b/util/ios/ios_intermediate_dump_format.h index 5e36862e8d..ea206430dd 100644 --- a/util/ios/ios_intermediate_dump_format.h +++ b/util/ios/ios_intermediate_dump_format.h @@ -99,6 +99,7 @@ namespace internal { TD(kThreadContextMemoryRegions, 6011) \ TD(kThreadContextMemoryRegionAddress, 6012) \ TD(kThreadContextMemoryRegionData, 6013) \ + TD(kThreadName, 6014) \ TD(kMaxValue, 65535) \ // clang-format on From 2bf08e6223b153592bc71685d09e0ec83af47cfb Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Tue, 14 Jun 2022 14:39:15 +0200 Subject: [PATCH 185/478] Detect blocked signal installation by sanitizers Sanitizers can prevent the installation of signal handlers, but sigaction would still return 0 (for success). Detect this by checking the installed signal handler via a second call to sigaction. R=mark@chromium.org Bug: chromium:1328749 Change-Id: I62a5777379ec5c6b1ca2d5a62e7cd3fb8ed1437b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3702302 Reviewed-by: Mark Mentovai Commit-Queue: Clemens Backes --- util/posix/signals.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/util/posix/signals.cc b/util/posix/signals.cc index f53ceb2a2f..93874e5426 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -147,6 +147,25 @@ bool Signals::InstallHandler(int sig, PLOG(ERROR) << "sigaction " << sig; return false; } + +// Sanitizers can prevent the installation of signal handlers, but sigaction +// does not report this as failure. Attempt to detect this by checking the +// currently installed signal handler. +#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ + defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \ + defined(UNDEFINED_SANITIZER) + struct sigaction installed_handler; + CHECK_EQ(sigaction(sig, nullptr, &installed_handler), 0); + // If the installed handler does not point to the just installed handler, then + // the allow_user_segv_handler sanitizer flag is (probably) disabled. + if (installed_handler.sa_sigaction != handler) { + LOG(WARNING) + << "sanitizers are preventing signal handler installation (sig " << sig + << ")"; + return false; + } +#endif + return true; } From f19ef3c6077e5318b723b92fa854c1000b3ba66f Mon Sep 17 00:00:00 2001 From: Alex Pankhurst Date: Mon, 13 Jun 2022 15:49:56 -0700 Subject: [PATCH 186/478] [fuchsia] Fix uninitialized fields Fuchsia's Crashpad roller was broken due to uninitialized fields in structs. Bug: fxbug.dev/101498 Change-Id: I1283afea9c5ac4eddb432590f9a5ec5cb1856a7c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3704517 Reviewed-by: Joshua Peraza Commit-Queue: Alex Pankhurst --- snapshot/fuchsia/process_reader_fuchsia_test.cc | 2 +- snapshot/minidump/process_snapshot_minidump_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index 3c8f827001..b8e71afb5f 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -147,7 +147,7 @@ CRASHPAD_CHILD_TEST_MAIN(ProcessReaderChildThreadsTestMain) { EXPECT_EQ(status, ZX_OK); constexpr size_t kNumThreads = 5; - struct ThreadData thread_data[kNumThreads] = {{0}}; + struct ThreadData thread_data[kNumThreads] = {{0, 0}}; for (size_t i = 0; i < kNumThreads; ++i) { thread_data[i] = { diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 902d699ee8..7fb4388820 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -792,7 +792,7 @@ TEST(ProcessSnapshotMinidump, ThreadsWithNames) { for (uint32_t minidump_thread_index = 0; minidump_thread_index < kMinidumpThreadCount; ++minidump_thread_index) { - MINIDUMP_THREAD_NAME minidump_thread_name = {0}; + MINIDUMP_THREAD_NAME minidump_thread_name = {0, 0}; minidump_thread_name.ThreadId = kBaseThreadId + minidump_thread_index; minidump_thread_name.RvaOfThreadName = thread_name_rva64s[minidump_thread_index]; From 02bdf8f9d75490eea23968818ed4e80c8b576c0b Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Mon, 13 Jun 2022 15:18:29 -0600 Subject: [PATCH 187/478] [snapshot] Add missing #include in process_reader_win_test.cc The Chromium presubmits flagged a missing #include in process_reader_win_test.cc. This adds the missing #include. Change-Id: I68aed4328f976bba547a0cb7a9ea833fdf71873b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3703312 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- snapshot/win/process_reader_win_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 6cfd8a4f45..f63277da76 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -25,6 +25,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/scoped_set_thread_name.h" From 3ae34b169b30c7cd47db244bb277f8c5fe0c06c6 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 14 Jun 2022 19:00:14 -0400 Subject: [PATCH 188/478] [test] Fix test build failures in Chromium Importing Crashpad into Chromium revealed a few build failures: 1) The MSVC compiler needed assistance constructing SleepingThreads 2) scoped_set_thread_name_posix.cc did not build on Android, where BUILDFLAG(IS_LINUX) is not defined and __ANDROID_API__ must be set to 24 or higher to use pthread_getname_np() This fixes the build failures, which I tested with a Chromium CQ dry-run: https://crrev.com/c/3703491 Change-Id: Ibde7cacaa45d384272890ea9b1ee2d707048ab03 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3703446 Commit-Queue: Mark Mentovai Reviewed-by: Joshua Peraza --- snapshot/win/process_reader_win_test.cc | 8 +++---- test/scoped_set_thread_name_posix.cc | 29 +++++++++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index f63277da76..98cb11b7af 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -145,7 +145,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { class SleepingThread : public Thread { public: - SleepingThread(const std::string& thread_name) + explicit SleepingThread(const std::string& thread_name) : done_(nullptr), thread_name_(thread_name) {} void SetHandle(Semaphore* done) { @@ -222,9 +222,9 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { // Create three dummy threads so we can confirm we read successfully read // more than just the main thread. std::array threads = { - "WinMultiprocessChild-1", - "WinMultiprocessChild-2", - "WinMultiprocessChild-3", + SleepingThread(std::string("WinMultiprocessChild-1")), + SleepingThread(std::string("WinMultiprocessChild-2")), + SleepingThread(std::string("WinMultiprocessChild-3")), }; Semaphore done(0); for (auto& thread : threads) diff --git a/test/scoped_set_thread_name_posix.cc b/test/scoped_set_thread_name_posix.cc index 66146c066a..4720bc0045 100644 --- a/test/scoped_set_thread_name_posix.cc +++ b/test/scoped_set_thread_name_posix.cc @@ -20,10 +20,13 @@ #include #include "base/check.h" +#include "base/check_op.h" #include "build/build_config.h" #if BUILDFLAG(IS_APPLE) #include +#elif BUILDFLAG(IS_ANDROID) +#include #endif namespace crashpad { @@ -31,36 +34,44 @@ namespace test { namespace { -#if BUILDFLAG(IS_LINUX) +#if BUILDFLAG(IS_APPLE) +constexpr size_t kPthreadNameMaxLen = MAXTHREADNAMESIZE; +#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) // The kernel headers define this in linux/sched.h as TASK_COMM_LEN, but the // userspace copy of that header does not define it. constexpr size_t kPthreadNameMaxLen = 16; -#elif BUILDFLAG(IS_APPLE) -constexpr size_t kPthreadNameMaxLen = MAXTHREADNAMESIZE; #else #error Port to your platform #endif void SetCurrentThreadName(const std::string& thread_name) { -#if BUILDFLAG(IS_LINUX) - PCHECK((errno = pthread_setname_np(pthread_self(), thread_name.c_str())) == 0) - << "pthread_setname_np"; -#elif BUILDFLAG(IS_APPLE) +#if BUILDFLAG(IS_APPLE) // Apple's pthread_setname_np() sets errno instead of returning it. PCHECK(pthread_setname_np(thread_name.c_str()) == 0) << "pthread_setname_np"; +#elif BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 24 + // pthread_setname_np() requires Android API 24 or later. + CHECK_LT(thread_name.length(), kPthreadNameMaxLen); + PCHECK(prctl(PR_SET_NAME, thread_name.c_str()) == 0) << "prctl(PR_SET_NAME)"; #else -#error Port to your platform + PCHECK((errno = pthread_setname_np(pthread_self(), thread_name.c_str())) == 0) + << "pthread_setname_np"; #endif } std::string GetCurrentThreadName() { std::string result(kPthreadNameMaxLen, '\0'); +#if BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 24 + static constexpr char kGetThreadNameFunctionName[] = "prctl"; + PCHECK(prctl(PR_GET_NAME, result.data()) == 0) << "prctl(PR_GET_NAME)"; +#else + static constexpr char kGetThreadNameFunctionName[] = "pthread_getname_np"; PCHECK((errno = pthread_getname_np( pthread_self(), result.data(), result.length())) == 0) << "pthread_getname_np"; +#endif const auto result_nul_idx = result.find('\0'); CHECK(result_nul_idx != std::string::npos) - << "pthread_getname_np did not NUL terminate"; + << kGetThreadNameFunctionName << " did not NUL terminate"; result.resize(result_nul_idx); return result; } From 99a5c423e76255e2e1fabcc50dc2e6148785bcde Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 15 Jun 2022 12:10:08 +0200 Subject: [PATCH 189/478] Fix windows client-stacktrace build by... switching to the new thread-context getter instead of the previously exposed union. For context: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3538668 --- snapshot/win/process_reader_win.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index cbcc6ba4a0..8704d3d733 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -153,7 +153,7 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, int machine_type = IMAGE_FILE_MACHINE_I386; LPVOID ctx = NULL; #if defined(ARCH_CPU_X86) - const CONTEXT* ctx_ = &thread->context.native; + const CONTEXT* ctx_ = thread->context.context(); stack_frame.AddrPC.Offset = ctx_->Eip; stack_frame.AddrFrame.Offset = ctx_->Ebp; stack_frame.AddrStack.Offset = ctx_->Esp; @@ -162,7 +162,7 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, // if (!is_64_reading_32) { machine_type = IMAGE_FILE_MACHINE_AMD64; - const CONTEXT* ctx_ = &thread->context.native; + const CONTEXT* ctx_ = thread->context.context(); stack_frame.AddrPC.Offset = ctx_->Rip; stack_frame.AddrFrame.Offset = ctx_->Rbp; stack_frame.AddrStack.Offset = ctx_->Rsp; From 86a1fa58c13d5d75b5191728fee710ef2ffc7716 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 15 Jun 2022 15:06:42 +0200 Subject: [PATCH 190/478] Fixing linux build by explicitly copying the thread_id from a packed... ...struct before "emplacing" it into the thread_names map in ProcessSnapshotMinidump::InitializeThreadNames(). --- snapshot/minidump/process_snapshot_minidump.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 28942447dc..4017c91bce 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -643,7 +643,19 @@ bool ProcessSnapshotMinidump::InitializeThreadNames() { return false; } - thread_names_.emplace(minidump_thread_name.ThreadId, std::move(name)); + // XXX sentry maintainers: + // the upstream line + // + // thread_names_.emplace(minidump_thread_name.ThreadId, std::move(name)); + // + // fails to compile on GCC (which is untested/-supported by the crashpad + // maintainers). emplace() takes its parameters as rvalue-references + // which is illegal when referencing a bitfield (or packed struct). + // + // Creating an explicit copy by-passes the issue, trading for more + // (typically two) instructions per thread-name. + uint32_t thread_id = minidump_thread_name.ThreadId; + thread_names_.emplace(thread_id, std::move(name)); } return true; From 07ef17371d476fc77e737813cfcb434fc4aabddd Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 15 Jun 2022 09:51:59 -0400 Subject: [PATCH 191/478] Add buildtools/clang_format/script to DEPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clang-format doesn’t work after week’s buildtools update to 0a14d52dad27 without separately checking out buildtools/clang_format/script. Change-Id: I8330aacb85d1ba96318e5f2cd4563b6d32615963 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3707851 Commit-Queue: Mark Mentovai Reviewed-by: Justin Cohen --- DEPS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DEPS b/DEPS index 9829da3433..4a2012548c 100644 --- a/DEPS +++ b/DEPS @@ -27,6 +27,10 @@ deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + '8b16338d17cd71b04a6ba28da7322ab6739892c2', + 'buildtools/clang_format/script': + Var('chromium_git') + + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@' + + 'c912837e0d82b5ca4b6e790b573b3956d3744c1c', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '727e556705278598fce683522beedbb9946bfda0', From 460943dd9a71dc76f68182a8ede766d5543e5341 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 16 Jun 2022 12:09:22 +0530 Subject: [PATCH 192/478] posix: Replace DoubleForkAndExec() with ForkAndSpawn() The DoubleForkAndExec() function was taking over 622 milliseconds to run on macOS 11 (BigSur) on Intel i5-1038NG7. I did some debugging by adding some custom traces and found that the fork() syscall is the bottleneck here, i.e., the first fork() takes around 359 milliseconds and the nested fork() takes around 263 milliseconds. Replacing the nested fork() and exec() with posix_spawn() reduces the time consumption to 257 milliseconds! See https://github.com/libuv/libuv/pull/3064 to know why fork() is so slow on macOS and why posix_spawn() is a better replacement. Another point to note is that even base::LaunchProcess() from Chromium calls posix_spawnp() on macOS - https://source.chromium.org/chromium/chromium/src/+/8f8d82dea0fa8f11f57c74dbb65126f8daba58f7:base/process/launch_mac.cc;l=295-296 Change-Id: I25c6ee9629a1ae5d0c32b361b56a1ce0b4b0fd26 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3641386 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- AUTHORS | 1 + client/crashpad_client_linux.cc | 10 +- client/crashpad_client_mac.cc | 4 +- .../cros_crash_report_exception_handler.cc | 13 +- util/BUILD.gn | 4 +- util/posix/double_fork_and_exec.cc | 166 ------------- util/posix/fork_and_spawn.cc | 235 ++++++++++++++++++ ...ouble_fork_and_exec.h => fork_and_spawn.h} | 29 +-- 8 files changed, 264 insertions(+), 198 deletions(-) delete mode 100644 util/posix/double_fork_and_exec.cc create mode 100644 util/posix/fork_and_spawn.cc rename util/posix/{double_fork_and_exec.h => fork_and_spawn.h} (76%) diff --git a/AUTHORS b/AUTHORS index 8dcac32388..0210392433 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,3 +12,4 @@ Opera Software ASA Vewd Software AS LG Electronics, Inc. MIPS Technologies, Inc. +Darshan Sen diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 295ec1615d..94c1cb02ef 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -45,7 +45,7 @@ #include "util/linux/socket.h" #include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" -#include "util/posix/double_fork_and_exec.h" +#include "util/posix/fork_and_spawn.h" #include "util/posix/scoped_mmap.h" #include "util/posix/signals.h" @@ -459,7 +459,7 @@ bool CrashpadClient::StartHandler( argv.push_back(FormatArgumentInt("initial-client-fd", handler_sock.get())); argv.push_back("--shared-client-connection"); - if (!DoubleForkAndExec(argv, nullptr, handler_sock.get(), false, nullptr)) { + if (!ForkAndSpawn(argv, nullptr, handler_sock.get(), false, nullptr)) { return false; } @@ -614,7 +614,7 @@ bool CrashpadClient::StartJavaHandlerForClient( int socket) { std::vector argv = BuildAppProcessArgs( class_name, database, metrics_dir, url, annotations, arguments, socket); - return DoubleForkAndExec(argv, env, socket, false, nullptr); + return ForkAndSpawn(argv, env, socket, false, nullptr); } bool CrashpadClient::StartHandlerWithLinkerAtCrash( @@ -663,7 +663,7 @@ bool CrashpadClient::StartHandlerWithLinkerForClient( annotations, arguments, socket); - return DoubleForkAndExec(argv, env, socket, false, nullptr); + return ForkAndSpawn(argv, env, socket, false, nullptr); } #endif @@ -697,7 +697,7 @@ bool CrashpadClient::StartHandlerForClient( argv.push_back(FormatArgumentInt("initial-client-fd", socket)); - return DoubleForkAndExec(argv, nullptr, socket, true, nullptr); + return ForkAndSpawn(argv, nullptr, socket, true, nullptr); } // static diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index d25bfb7163..585bac910a 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -36,7 +36,7 @@ #include "util/mach/notify_server.h" #include "util/misc/clock.h" #include "util/misc/implicit_cast.h" -#include "util/posix/double_fork_and_exec.h" +#include "util/posix/fork_and_spawn.h" namespace crashpad { @@ -343,7 +343,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { // this parent process, which was probably using the exception server now // being restarted. The handler can’t monitor itself for its own crashes via // this interface. - if (!DoubleForkAndExec( + if (!ForkAndSpawn( argv, nullptr, server_write_fd.get(), diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index 9e58d94aa4..3caa3b987b 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -29,7 +29,7 @@ #include "util/linux/ptrace_client.h" #include "util/misc/metrics.h" #include "util/misc/uuid.h" -#include "util/posix/double_fork_and_exec.h" +#include "util/posix/fork_and_spawn.h" namespace crashpad { @@ -266,12 +266,11 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( argv.push_back("--always_allow_feedback"); } - if (!DoubleForkAndExec(argv, - nullptr /* envp */, - file_writer.fd() /* preserve_fd */, - false /* use_path */, - nullptr /* child_function */)) { - LOG(ERROR) << "DoubleForkAndExec failed"; + if (!ForkAndSpawn(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return false; diff --git a/util/BUILD.gn b/util/BUILD.gn index c372ff49b3..79cf878e43 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -288,10 +288,10 @@ crashpad_static_library("util") { sources += [ "posix/close_multiple.cc", "posix/close_multiple.h", - "posix/double_fork_and_exec.cc", - "posix/double_fork_and_exec.h", "posix/drop_privileges.cc", "posix/drop_privileges.h", + "posix/fork_and_spawn.cc", + "posix/fork_and_spawn.h", "posix/process_info.h", # These map signals to and from strings. While Fuchsia defines some of diff --git a/util/posix/double_fork_and_exec.cc b/util/posix/double_fork_and_exec.cc deleted file mode 100644 index 1960430954..0000000000 --- a/util/posix/double_fork_and_exec.cc +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2017 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "util/posix/double_fork_and_exec.h" - -#include -#include -#include -#include - -#include "base/check_op.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/stringprintf.h" -#include "util/posix/close_multiple.h" - -namespace crashpad { - -bool DoubleForkAndExec(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()) { - DCHECK(!envp || !use_path); - - // argv_c contains const char* pointers and is terminated by nullptr. This is - // suitable for passing to execv(). Although argv_c is not used in the parent - // process, it must be built in the parent process because it’s unsafe to do - // so in the child or grandchild process. - std::vector argv_c; - argv_c.reserve(argv.size() + 1); - for (const std::string& argument : argv) { - argv_c.push_back(argument.c_str()); - } - argv_c.push_back(nullptr); - - std::vector envp_c; - if (envp) { - envp_c.reserve(envp->size() + 1); - for (const std::string& variable : *envp) { - envp_c.push_back(variable.c_str()); - } - envp_c.push_back(nullptr); - } - - // Double-fork(). The three processes involved are parent, child, and - // grandchild. The grandchild will call execv(). The child exits immediately - // after spawning the grandchild, so the grandchild becomes an orphan and its - // parent process ID becomes 1. This relieves the parent and child of the - // responsibility to reap the grandchild with waitpid() or similar. The - // grandchild is expected to outlive the parent process, so the parent - // shouldn’t be concerned with reaping it. This approach means that accidental - // early termination of the handler process will not result in a zombie - // process. - pid_t pid = fork(); - if (pid < 0) { - PLOG(ERROR) << "fork"; - return false; - } - - if (pid == 0) { - // Child process. - - if (child_function) { - child_function(); - } - - // Call setsid(), creating a new process group and a new session, both led - // by this process. The new process group has no controlling terminal. This - // disconnects it from signals generated by the parent process’ terminal. - // - // setsid() is done in the child instead of the grandchild so that the - // grandchild will not be a session leader. If it were a session leader, an - // accidental open() of a terminal device without O_NOCTTY would make that - // terminal the controlling terminal. - // - // It’s not desirable for the grandchild to have a controlling terminal. The - // grandchild manages its own lifetime, such as by monitoring clients on its - // own and exiting when it loses all clients and when it deems it - // appropraite to do so. It may serve clients in different process groups or - // sessions than its original client, and receiving signals intended for its - // original client’s process group could be harmful in that case. - PCHECK(setsid() != -1) << "setsid"; - - pid = fork(); - if (pid < 0) { - PLOG(FATAL) << "fork"; - } - - if (pid > 0) { - // Child process. - - // _exit() instead of exit(), because fork() was called. - _exit(EXIT_SUCCESS); - } - - // Grandchild process. - - CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); - - // &argv_c[0] is a pointer to a pointer to const char data, but because of - // how C (not C++) works, execvp() wants a pointer to a const pointer to - // char data. It modifies neither the data nor the pointers, so the - // const_cast is safe. - char* const* argv_for_execv = const_cast(&argv_c[0]); - - if (envp) { - // This cast is safe for the same reason that the argv_for_execv cast is. - char* const* envp_for_execv = const_cast(&envp_c[0]); - execve(argv_for_execv[0], argv_for_execv, envp_for_execv); - PLOG(FATAL) << "execve " << argv_for_execv[0]; - } - - if (use_path) { - execvp(argv_for_execv[0], argv_for_execv); - PLOG(FATAL) << "execvp " << argv_for_execv[0]; - } - - execv(argv_for_execv[0], argv_for_execv); - PLOG(FATAL) << "execv " << argv_for_execv[0]; - } - - // waitpid() for the child, so that it does not become a zombie process. The - // child normally exits quickly. - // - // Failures from this point on may result in the accumulation of a zombie, but - // should not be considered fatal. Log only warnings, but don’t treat these - // failures as a failure of the function overall. - int status; - pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); - if (wait_pid == -1) { - PLOG(WARNING) << "waitpid"; - return true; - } - DCHECK_EQ(wait_pid, pid); - - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); - LOG(WARNING) << base::StringPrintf( - "intermediate process terminated by signal %d (%s)%s", - sig, - strsignal(sig), - WCOREDUMP(status) ? " (core dumped)" : ""); - } else if (!WIFEXITED(status)) { - LOG(WARNING) << base::StringPrintf( - "intermediate process: unknown termination 0x%x", status); - } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { - LOG(WARNING) << "intermediate process exited with code " - << WEXITSTATUS(status); - } - - return true; -} - -} // namespace crashpad diff --git a/util/posix/fork_and_spawn.cc b/util/posix/fork_and_spawn.cc new file mode 100644 index 0000000000..c6a95bbfdc --- /dev/null +++ b/util/posix/fork_and_spawn.cc @@ -0,0 +1,235 @@ +// Copyright 2017 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/posix/fork_and_spawn.h" + +#include +#include +#include +#include +#include +#include + +#include "base/check.h" +#include "base/check_op.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "util/posix/close_multiple.h" + +extern char** environ; + +namespace crashpad { + +namespace { + +#if BUILDFLAG(IS_APPLE) + +class PosixSpawnAttr { + public: + PosixSpawnAttr() { + PCHECK((errno = posix_spawnattr_init(&attr_)) == 0) + << "posix_spawnattr_init"; + } + + PosixSpawnAttr(const PosixSpawnAttr&) = delete; + PosixSpawnAttr& operator=(const PosixSpawnAttr&) = delete; + + ~PosixSpawnAttr() { + PCHECK((errno = posix_spawnattr_destroy(&attr_)) == 0) + << "posix_spawnattr_destroy"; + } + + void SetFlags(short flags) { + PCHECK((errno = posix_spawnattr_setflags(&attr_, flags)) == 0) + << "posix_spawnattr_setflags"; + } + + const posix_spawnattr_t* Get() const { return &attr_; } + + private: + posix_spawnattr_t attr_; +}; + +class PosixSpawnFileActions { + public: + PosixSpawnFileActions() { + PCHECK((errno = posix_spawn_file_actions_init(&file_actions_)) == 0) + << "posix_spawn_file_actions_init"; + } + + PosixSpawnFileActions(const PosixSpawnFileActions&) = delete; + PosixSpawnFileActions& operator=(const PosixSpawnFileActions&) = delete; + + ~PosixSpawnFileActions() { + PCHECK((errno = posix_spawn_file_actions_destroy(&file_actions_)) == 0) + << "posix_spawn_file_actions_destroy"; + } + + void AddInheritedFileDescriptor(int fd) { + PCHECK((errno = posix_spawn_file_actions_addinherit_np(&file_actions_, + fd)) == 0) + << "posix_spawn_file_actions_addinherit_np"; + } + + const posix_spawn_file_actions_t* Get() const { return &file_actions_; } + + private: + posix_spawn_file_actions_t file_actions_; +}; + +#endif + +} // namespace + +bool ForkAndSpawn(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()) { + // argv_c contains const char* pointers and is terminated by nullptr. This is + // suitable for passing to posix_spawn() or posix_spawnp(). Although argv_c is + // not used in the parent process, it must be built in the parent process + // because it’s unsafe to do so in the child. + std::vector argv_c; + argv_c.reserve(argv.size() + 1); + for (const std::string& argument : argv) { + argv_c.push_back(argument.c_str()); + } + argv_c.push_back(nullptr); + + std::vector envp_c; + if (envp) { + envp_c.reserve(envp->size() + 1); + for (const std::string& variable : *envp) { + envp_c.push_back(variable.c_str()); + } + envp_c.push_back(nullptr); + } + + // The three processes involved are parent, child, and grandchild. The child + // exits immediately after spawning the grandchild, so the grandchild becomes + // an orphan and its parent process ID becomes 1. This relieves the parent and + // child of the responsibility to reap the grandchild with waitpid() or + // similar. The grandchild is expected to outlive the parent process, so the + // parent shouldn’t be concerned with reaping it. This approach means that + // accidental early termination of the handler process will not result in a + // zombie process. + pid_t pid = fork(); + if (pid < 0) { + PLOG(ERROR) << "fork"; + return false; + } + + if (pid == 0) { + // Child process. + + if (child_function) { + child_function(); + } + + // Call setsid(), creating a new process group and a new session, both led + // by this process. The new process group has no controlling terminal. This + // disconnects it from signals generated by the parent process’ terminal. + // + // setsid() is done in the child instead of the grandchild so that the + // grandchild will not be a session leader. If it were a session leader, an + // accidental open() of a terminal device without O_NOCTTY would make that + // terminal the controlling terminal. + // + // It’s not desirable for the grandchild to have a controlling terminal. The + // grandchild manages its own lifetime, such as by monitoring clients on its + // own and exiting when it loses all clients and when it deems it + // appropraite to do so. It may serve clients in different process groups or + // sessions than its original client, and receiving signals intended for its + // original client’s process group could be harmful in that case. + PCHECK(setsid() != -1) << "setsid"; + + // &argv_c[0] is a pointer to a pointer to const char data, but because of + // how C (not C++) works, posix_spawn() and posix_spawnp() want a pointer to + // a const pointer to char data. They modifies neither the data nor the + // pointers, so the const_cast is safe. + char* const* argv_for_spawn = const_cast(argv_c.data()); + + // This cast is safe for the same reason that the argv_for_spawn cast is. + char* const* envp_for_spawn = + envp ? const_cast(envp_c.data()) : environ; + +#if BUILDFLAG(IS_APPLE) + PosixSpawnAttr attr; + attr.SetFlags(POSIX_SPAWN_CLOEXEC_DEFAULT); + + PosixSpawnFileActions file_actions; + for (int fd = 0; fd <= STDERR_FILENO; ++fd) { + file_actions.AddInheritedFileDescriptor(fd); + } + file_actions.AddInheritedFileDescriptor(preserve_fd); + + const posix_spawnattr_t* attr_p = attr.Get(); + const posix_spawn_file_actions_t* file_actions_p = file_actions.Get(); +#else + CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); + + const posix_spawnattr_t* attr_p = nullptr; + const posix_spawn_file_actions_t* file_actions_p = nullptr; +#endif + + auto posix_spawn_fp = use_path ? posix_spawnp : posix_spawn; + if ((errno = posix_spawn_fp(&pid, + argv_for_spawn[0], + file_actions_p, + attr_p, + argv_for_spawn, + envp_for_spawn)) != 0) { + PLOG(FATAL) << (use_path ? "posix_spawnp" : "posix_spawn"); + } + + // _exit() instead of exit(), because fork() was called. + _exit(EXIT_SUCCESS); + } + + // waitpid() for the child, so that it does not become a zombie process. The + // child normally exits quickly. + // + // Failures from this point on may result in the accumulation of a zombie, but + // should not be considered fatal. Log only warnings, but don’t treat these + // failures as a failure of the function overall. + int status; + pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); + if (wait_pid == -1) { + PLOG(WARNING) << "waitpid"; + return true; + } + DCHECK_EQ(wait_pid, pid); + + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + LOG(WARNING) << base::StringPrintf( + "intermediate process terminated by signal %d (%s)%s", + sig, + strsignal(sig), + WCOREDUMP(status) ? " (core dumped)" : ""); + } else if (!WIFEXITED(status)) { + LOG(WARNING) << base::StringPrintf( + "intermediate process: unknown termination 0x%x", status); + } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { + LOG(WARNING) << "intermediate process exited with code " + << WEXITSTATUS(status); + } + + return true; +} + +} // namespace crashpad diff --git a/util/posix/double_fork_and_exec.h b/util/posix/fork_and_spawn.h similarity index 76% rename from util/posix/double_fork_and_exec.h rename to util/posix/fork_and_spawn.h index 02fc0f28f1..fc55aa3a37 100644 --- a/util/posix/double_fork_and_exec.h +++ b/util/posix/fork_and_spawn.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ -#define CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ +#ifndef CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ +#define CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ #include #include @@ -23,7 +23,7 @@ namespace crashpad { //! \brief Executes a (grand-)child process. //! //! The grandchild process will be started through the -//! double-`fork()`-and-`execv()` pattern. This allows the grandchild to fully +//! `fork()`-and-`posix_spawn()` pattern. This allows the grandchild to fully //! disassociate from the parent. The grandchild will not be a member of the //! parent’s process group or session and will not have a controlling terminal, //! providing isolation from signals not intended for it. The grandchild’s @@ -37,7 +37,7 @@ namespace crashpad { //! \param[in] argv The argument vector to start the grandchild process with. //! `argv[0]` is used as the path to the executable. //! \param[in] envp A vector of environment variables of the form `var=value` to -//! be passed to `execve()`. If this value is `nullptr`, the current +//! be passed to `posix_spawn()`. If this value is `nullptr`, the current //! environment is used. //! \param[in] preserve_fd A file descriptor to be inherited by the grandchild //! process. This file descriptor is inherited in addition to the three file @@ -45,16 +45,13 @@ namespace crashpad { //! if no additional file descriptors are to be inherited. //! \param[in] use_path Whether to consult the `PATH` environment variable when //! requested to start an executable at a non-absolute path. If `false`, -//! `execv()`, which does not consult `PATH`, will be used. If `true`, -//! `execvp()`, which does consult `PATH`, will be used. +//! `posix_spawn()`, which does not consult `PATH`, will be used. If `true`, +//! `posix_spawnp()`, which does consult `PATH`, will be used. //! \param[in] child_function If not `nullptr`, this function will be called in -//! the intermediate child process, prior to the second `fork()`. Take note +//! the intermediate child process, prior to the `posix_spawn()`. Take note //! that this function will run in the context of a forked process, and must //! be safe for that purpose. //! -//! Setting both \a envp to a value other than `nullptr` and \a use_path to -//! `true` is not currently supported. -//! //! \return `true` on success, and `false` on failure with a message logged. //! Only failures that occur in the parent process that indicate a definite //! failure to start the the grandchild are reported in the return value. @@ -63,12 +60,12 @@ namespace crashpad { //! terminating. The caller assumes the responsibility for detecting such //! failures, for example, by observing a failure to perform a successful //! handshake with the grandchild process. -bool DoubleForkAndExec(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()); +bool ForkAndSpawn(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()); } // namespace crashpad -#endif // CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ +#endif // CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ From 7c30a508eb1c5fba3533a1e5570e79b9b2ad37d5 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 17 Jun 2022 07:39:41 -0400 Subject: [PATCH 193/478] Build actual crashpad .asm files in win/cross builds Now that we have llvm-ml, we no longer need the workaround for this. This upstreams https://chromium-review.googlesource.com/c/chromium/src/+/3708412 Bug: chromium:762167 Change-Id: Iadc8ba9753bb7dd079415ee744f3b176b7e2f629 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3707748 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- util/BUILD.gn | 47 ++++++++--------------- util/misc/capture_context_broken.cc | 29 -------------- util/win/safe_terminate_process_broken.cc | 34 ---------------- 3 files changed, 15 insertions(+), 95 deletions(-) delete mode 100644 util/misc/capture_context_broken.cc delete mode 100644 util/win/safe_terminate_process_broken.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index 79cf878e43..17406edb0b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -509,40 +509,23 @@ crashpad_static_library("util") { "win/xp_compat.h", ] - # There's no ml.exe yet in cross builds, so provide broken-but-not-asm - # versions of the functions defined in .asm files. - # - # CaptureContext() in capture_context_broken.cc just calls CHECK(false). - # SafeTerminateProcess() in safe_terminate_process.cc just calls regular - # TerminateProcess() without the protection against broken third-party - # patching of TerminateProcess(). - # - # TODO(thakis): Use the .asm file in cross builds somehow, - # https://crbug.com/762167. - if (host_os == "win") { - if (current_cpu != "arm64") { - sources += [ - "misc/capture_context_win.asm", - "win/safe_terminate_process.asm", - ] - } else { - # Most Crashpad builds use Microsoft's armasm64.exe macro assembler for - # .asm source files. When building in Chromium, clang-cl is used as the - # assembler instead. Since the two assemblers recognize different - # assembly dialects, the same .asm file can't be used for each. As a - # workaround, use a prebuilt .obj file when the Microsoft-dialect - # assembler isn't available. - if (crashpad_is_in_chromium) { - sources += [ "misc/capture_context_win_arm64.obj" ] - } else { - sources += [ "misc/capture_context_win_arm64.asm" ] - } - } - } else { + if (current_cpu != "arm64") { sources += [ - "misc/capture_context_broken.cc", - "win/safe_terminate_process_broken.cc", + "misc/capture_context_win.asm", + "win/safe_terminate_process.asm", ] + } else { + # Most Crashpad builds use Microsoft's armasm64.exe macro assembler for + # .asm source files. When building in Chromium, clang-cl is used as the + # assembler instead. Since the two assemblers recognize different + # assembly dialects, the same .asm file can't be used for each. As a + # workaround, use a prebuilt .obj file when the Microsoft-dialect + # assembler isn't available. + if (crashpad_is_in_chromium) { + sources += [ "misc/capture_context_win_arm64.obj" ] + } else { + sources += [ "misc/capture_context_win_arm64.asm" ] + } } } diff --git a/util/misc/capture_context_broken.cc b/util/misc/capture_context_broken.cc deleted file mode 100644 index ea6d0a0cf9..0000000000 --- a/util/misc/capture_context_broken.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "util/misc/capture_context.h" - -#include - -#include "base/check.h" - -namespace crashpad { - -void CaptureContext(NativeCPUContext* context) { - // Don't use this file in production. - CHECK(false) - << "Don't use this! For cross builds only. See https://crbug.com/762167."; -} - -} // namespace crashpad diff --git a/util/win/safe_terminate_process_broken.cc b/util/win/safe_terminate_process_broken.cc deleted file mode 100644 index 2429c726ca..0000000000 --- a/util/win/safe_terminate_process_broken.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "util/win/safe_terminate_process.h" - -#include "base/logging.h" - -#if defined(ARCH_CPU_X86) - -namespace crashpad { - -bool SafeTerminateProcess(HANDLE process, UINT exit_code) { - // Third-party software that hooks TerminateProcess() incorrectly has been - // encountered in the wild. This version of SafeTerminateProcess() lacks - // protection against that, so don't use it in production. - LOG(WARNING) - << "Don't use this! For cross builds only. See https://crbug.com/777924."; - return TerminateProcess(process, exit_code) != FALSE; -} - -} // namespace crashpad - -#endif // defined(ARCH_CPU_X86) From 21546d85140d9e19689707a88c092e7c5eace1c8 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 22 Jun 2022 12:22:26 -0400 Subject: [PATCH 194/478] Use call_once in lazy settings load. This fixes a test case that accesses settings for the first time in multiple threads simultaneously. Fixed: crashpad:417 Change-Id: I6539682f171563f8ff5a1203fdd550ab92afc276 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3711807 Commit-Queue: Justin Cohen Reviewed-by: Robert Sesek --- client/crash_report_database_generic.cc | 7 ++++--- client/crash_report_database_mac.mm | 9 +++++---- client/crash_report_database_win.cc | 9 +++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index c4e0401096..742850ab87 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -258,15 +259,15 @@ class CrashReportDatabaseGeneric : public CrashReportDatabase { static bool WriteMetadata(const base::FilePath& path, const Report& report); Settings& SettingsInternal() { - if (!settings_init_) + std::call_once(settings_init_, [this]() { settings_.Initialize(base_dir_.Append(kSettings)); - settings_init_ = true; + }); return settings_; } base::FilePath base_dir_; Settings settings_; - bool settings_init_ = false; + std::once_flag settings_init_; InitializationStateDcheck initialized_; }; diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 4c9e5e72e8..e33b932528 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -27,6 +27,7 @@ #include #include +#include #include #include "base/logging.h" @@ -263,15 +264,15 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, void CleanOrphanedAttachments(); Settings& SettingsInternal() { - if (!settings_init_) + std::call_once(settings_init_, [this]() { settings_.Initialize(base_dir_.Append(kSettings)); - settings_init_ = true; + }); return settings_; } base::FilePath base_dir_; Settings settings_; - bool settings_init_; + std::once_flag settings_init_; bool xattr_new_names_; InitializationStateDcheck initialized_; }; @@ -280,7 +281,7 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, : CrashReportDatabase(), base_dir_(path), settings_(), - settings_init_(false), + settings_init_(), xattr_new_names_(false), initialized_() {} diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index e16aa104fb..e111d8e13b 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -663,15 +664,15 @@ class CrashReportDatabaseWin : public CrashReportDatabase { std::unique_ptr AcquireMetadata(); Settings& SettingsInternal() { - if (!settings_init_) + std::call_once(settings_init_, [this]() { settings_.Initialize(base_dir_.Append(kSettings)); - settings_init_ = true; + }); return settings_; } base::FilePath base_dir_; Settings settings_; - bool settings_init_; + std::once_flag settings_init_; InitializationStateDcheck initialized_; }; @@ -679,7 +680,7 @@ CrashReportDatabaseWin::CrashReportDatabaseWin(const base::FilePath& path) : CrashReportDatabase(), base_dir_(path), settings_(), - settings_init_(false), + settings_init_(), initialized_() {} CrashReportDatabaseWin::~CrashReportDatabaseWin() { From 23cefd04177be4020c00edc681d1765b76e2cd0b Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 22 Jun 2022 19:34:31 -0400 Subject: [PATCH 195/478] Fix Chromium compile. Fixes error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream') and 'const char[19]') << "pthread_setname_np"; in test/scoped_set_thread_name_posix.cc Change-Id: I77eeeee9c828d563aaa15331733001e522a04642 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3714964 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- test/scoped_set_thread_name_posix.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/scoped_set_thread_name_posix.cc b/test/scoped_set_thread_name_posix.cc index 4720bc0045..92c61bbf41 100644 --- a/test/scoped_set_thread_name_posix.cc +++ b/test/scoped_set_thread_name_posix.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include "base/check.h" From 6e946c4af851722b9d444af89590d65cd2c3ec38 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 23 Jun 2022 03:12:41 +0000 Subject: [PATCH 196/478] Revert "posix: Replace DoubleForkAndExec() with ForkAndSpawn()" This reverts commit 460943dd9a71dc76f68182a8ede766d5543e5341. Reason for revert: This fails to compile in Chromium Android. posix_spawn and posix_spawnp are available in Android NDK 28, but Chromium is building with version 23. https://ci.chromium.org/ui/p/chromium/builders/try/android_compile_dbg/1179765/overview Original change's description: > posix: Replace DoubleForkAndExec() with ForkAndSpawn() > > The DoubleForkAndExec() function was taking over 622 milliseconds to run > on macOS 11 (BigSur) on Intel i5-1038NG7. I did some debugging by adding > some custom traces and found that the fork() syscall is the bottleneck > here, i.e., the first fork() takes around 359 milliseconds and the > nested fork() takes around 263 milliseconds. Replacing the nested fork() > and exec() with posix_spawn() reduces the time consumption to 257 > milliseconds! > > See https://github.com/libuv/libuv/pull/3064 to know why fork() is so > slow on macOS and why posix_spawn() is a better replacement. > > Another point to note is that even base::LaunchProcess() from Chromium > calls posix_spawnp() on macOS - > https://source.chromium.org/chromium/chromium/src/+/8f8d82dea0fa8f11f57c74dbb65126f8daba58f7:base/process/launch_mac.cc;l=295-296 > > Change-Id: I25c6ee9629a1ae5d0c32b361b56a1ce0b4b0fd26 > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3641386 > Reviewed-by: Mark Mentovai > Commit-Queue: Mark Mentovai Change-Id: I7f6161bc4734c50308438cdde1e193023ee9bfb8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3719439 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- AUTHORS | 1 - client/crashpad_client_linux.cc | 10 +- client/crashpad_client_mac.cc | 4 +- .../cros_crash_report_exception_handler.cc | 13 +- util/BUILD.gn | 4 +- util/posix/double_fork_and_exec.cc | 166 +++++++++++++ ...ork_and_spawn.h => double_fork_and_exec.h} | 29 ++- util/posix/fork_and_spawn.cc | 235 ------------------ 8 files changed, 198 insertions(+), 264 deletions(-) create mode 100644 util/posix/double_fork_and_exec.cc rename util/posix/{fork_and_spawn.h => double_fork_and_exec.h} (76%) delete mode 100644 util/posix/fork_and_spawn.cc diff --git a/AUTHORS b/AUTHORS index 0210392433..8dcac32388 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,4 +12,3 @@ Opera Software ASA Vewd Software AS LG Electronics, Inc. MIPS Technologies, Inc. -Darshan Sen diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 94c1cb02ef..295ec1615d 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -45,7 +45,7 @@ #include "util/linux/socket.h" #include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" -#include "util/posix/fork_and_spawn.h" +#include "util/posix/double_fork_and_exec.h" #include "util/posix/scoped_mmap.h" #include "util/posix/signals.h" @@ -459,7 +459,7 @@ bool CrashpadClient::StartHandler( argv.push_back(FormatArgumentInt("initial-client-fd", handler_sock.get())); argv.push_back("--shared-client-connection"); - if (!ForkAndSpawn(argv, nullptr, handler_sock.get(), false, nullptr)) { + if (!DoubleForkAndExec(argv, nullptr, handler_sock.get(), false, nullptr)) { return false; } @@ -614,7 +614,7 @@ bool CrashpadClient::StartJavaHandlerForClient( int socket) { std::vector argv = BuildAppProcessArgs( class_name, database, metrics_dir, url, annotations, arguments, socket); - return ForkAndSpawn(argv, env, socket, false, nullptr); + return DoubleForkAndExec(argv, env, socket, false, nullptr); } bool CrashpadClient::StartHandlerWithLinkerAtCrash( @@ -663,7 +663,7 @@ bool CrashpadClient::StartHandlerWithLinkerForClient( annotations, arguments, socket); - return ForkAndSpawn(argv, env, socket, false, nullptr); + return DoubleForkAndExec(argv, env, socket, false, nullptr); } #endif @@ -697,7 +697,7 @@ bool CrashpadClient::StartHandlerForClient( argv.push_back(FormatArgumentInt("initial-client-fd", socket)); - return ForkAndSpawn(argv, nullptr, socket, true, nullptr); + return DoubleForkAndExec(argv, nullptr, socket, true, nullptr); } // static diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 585bac910a..d25bfb7163 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -36,7 +36,7 @@ #include "util/mach/notify_server.h" #include "util/misc/clock.h" #include "util/misc/implicit_cast.h" -#include "util/posix/fork_and_spawn.h" +#include "util/posix/double_fork_and_exec.h" namespace crashpad { @@ -343,7 +343,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { // this parent process, which was probably using the exception server now // being restarted. The handler can’t monitor itself for its own crashes via // this interface. - if (!ForkAndSpawn( + if (!DoubleForkAndExec( argv, nullptr, server_write_fd.get(), diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index 3caa3b987b..9e58d94aa4 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -29,7 +29,7 @@ #include "util/linux/ptrace_client.h" #include "util/misc/metrics.h" #include "util/misc/uuid.h" -#include "util/posix/fork_and_spawn.h" +#include "util/posix/double_fork_and_exec.h" namespace crashpad { @@ -266,11 +266,12 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( argv.push_back("--always_allow_feedback"); } - if (!ForkAndSpawn(argv, - nullptr /* envp */, - file_writer.fd() /* preserve_fd */, - false /* use_path */, - nullptr /* child_function */)) { + 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; diff --git a/util/BUILD.gn b/util/BUILD.gn index 17406edb0b..3fe82c395e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -288,10 +288,10 @@ crashpad_static_library("util") { sources += [ "posix/close_multiple.cc", "posix/close_multiple.h", + "posix/double_fork_and_exec.cc", + "posix/double_fork_and_exec.h", "posix/drop_privileges.cc", "posix/drop_privileges.h", - "posix/fork_and_spawn.cc", - "posix/fork_and_spawn.h", "posix/process_info.h", # These map signals to and from strings. While Fuchsia defines some of diff --git a/util/posix/double_fork_and_exec.cc b/util/posix/double_fork_and_exec.cc new file mode 100644 index 0000000000..1960430954 --- /dev/null +++ b/util/posix/double_fork_and_exec.cc @@ -0,0 +1,166 @@ +// Copyright 2017 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/posix/double_fork_and_exec.h" + +#include +#include +#include +#include + +#include "base/check_op.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/strings/stringprintf.h" +#include "util/posix/close_multiple.h" + +namespace crashpad { + +bool DoubleForkAndExec(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()) { + DCHECK(!envp || !use_path); + + // argv_c contains const char* pointers and is terminated by nullptr. This is + // suitable for passing to execv(). Although argv_c is not used in the parent + // process, it must be built in the parent process because it’s unsafe to do + // so in the child or grandchild process. + std::vector argv_c; + argv_c.reserve(argv.size() + 1); + for (const std::string& argument : argv) { + argv_c.push_back(argument.c_str()); + } + argv_c.push_back(nullptr); + + std::vector envp_c; + if (envp) { + envp_c.reserve(envp->size() + 1); + for (const std::string& variable : *envp) { + envp_c.push_back(variable.c_str()); + } + envp_c.push_back(nullptr); + } + + // Double-fork(). The three processes involved are parent, child, and + // grandchild. The grandchild will call execv(). The child exits immediately + // after spawning the grandchild, so the grandchild becomes an orphan and its + // parent process ID becomes 1. This relieves the parent and child of the + // responsibility to reap the grandchild with waitpid() or similar. The + // grandchild is expected to outlive the parent process, so the parent + // shouldn’t be concerned with reaping it. This approach means that accidental + // early termination of the handler process will not result in a zombie + // process. + pid_t pid = fork(); + if (pid < 0) { + PLOG(ERROR) << "fork"; + return false; + } + + if (pid == 0) { + // Child process. + + if (child_function) { + child_function(); + } + + // Call setsid(), creating a new process group and a new session, both led + // by this process. The new process group has no controlling terminal. This + // disconnects it from signals generated by the parent process’ terminal. + // + // setsid() is done in the child instead of the grandchild so that the + // grandchild will not be a session leader. If it were a session leader, an + // accidental open() of a terminal device without O_NOCTTY would make that + // terminal the controlling terminal. + // + // It’s not desirable for the grandchild to have a controlling terminal. The + // grandchild manages its own lifetime, such as by monitoring clients on its + // own and exiting when it loses all clients and when it deems it + // appropraite to do so. It may serve clients in different process groups or + // sessions than its original client, and receiving signals intended for its + // original client’s process group could be harmful in that case. + PCHECK(setsid() != -1) << "setsid"; + + pid = fork(); + if (pid < 0) { + PLOG(FATAL) << "fork"; + } + + if (pid > 0) { + // Child process. + + // _exit() instead of exit(), because fork() was called. + _exit(EXIT_SUCCESS); + } + + // Grandchild process. + + CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); + + // &argv_c[0] is a pointer to a pointer to const char data, but because of + // how C (not C++) works, execvp() wants a pointer to a const pointer to + // char data. It modifies neither the data nor the pointers, so the + // const_cast is safe. + char* const* argv_for_execv = const_cast(&argv_c[0]); + + if (envp) { + // This cast is safe for the same reason that the argv_for_execv cast is. + char* const* envp_for_execv = const_cast(&envp_c[0]); + execve(argv_for_execv[0], argv_for_execv, envp_for_execv); + PLOG(FATAL) << "execve " << argv_for_execv[0]; + } + + if (use_path) { + execvp(argv_for_execv[0], argv_for_execv); + PLOG(FATAL) << "execvp " << argv_for_execv[0]; + } + + execv(argv_for_execv[0], argv_for_execv); + PLOG(FATAL) << "execv " << argv_for_execv[0]; + } + + // waitpid() for the child, so that it does not become a zombie process. The + // child normally exits quickly. + // + // Failures from this point on may result in the accumulation of a zombie, but + // should not be considered fatal. Log only warnings, but don’t treat these + // failures as a failure of the function overall. + int status; + pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); + if (wait_pid == -1) { + PLOG(WARNING) << "waitpid"; + return true; + } + DCHECK_EQ(wait_pid, pid); + + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + LOG(WARNING) << base::StringPrintf( + "intermediate process terminated by signal %d (%s)%s", + sig, + strsignal(sig), + WCOREDUMP(status) ? " (core dumped)" : ""); + } else if (!WIFEXITED(status)) { + LOG(WARNING) << base::StringPrintf( + "intermediate process: unknown termination 0x%x", status); + } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { + LOG(WARNING) << "intermediate process exited with code " + << WEXITSTATUS(status); + } + + return true; +} + +} // namespace crashpad diff --git a/util/posix/fork_and_spawn.h b/util/posix/double_fork_and_exec.h similarity index 76% rename from util/posix/fork_and_spawn.h rename to util/posix/double_fork_and_exec.h index fc55aa3a37..02fc0f28f1 100644 --- a/util/posix/fork_and_spawn.h +++ b/util/posix/double_fork_and_exec.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ -#define CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ +#ifndef CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ +#define CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ #include #include @@ -23,7 +23,7 @@ namespace crashpad { //! \brief Executes a (grand-)child process. //! //! The grandchild process will be started through the -//! `fork()`-and-`posix_spawn()` pattern. This allows the grandchild to fully +//! double-`fork()`-and-`execv()` pattern. This allows the grandchild to fully //! disassociate from the parent. The grandchild will not be a member of the //! parent’s process group or session and will not have a controlling terminal, //! providing isolation from signals not intended for it. The grandchild’s @@ -37,7 +37,7 @@ namespace crashpad { //! \param[in] argv The argument vector to start the grandchild process with. //! `argv[0]` is used as the path to the executable. //! \param[in] envp A vector of environment variables of the form `var=value` to -//! be passed to `posix_spawn()`. If this value is `nullptr`, the current +//! be passed to `execve()`. If this value is `nullptr`, the current //! environment is used. //! \param[in] preserve_fd A file descriptor to be inherited by the grandchild //! process. This file descriptor is inherited in addition to the three file @@ -45,13 +45,16 @@ namespace crashpad { //! if no additional file descriptors are to be inherited. //! \param[in] use_path Whether to consult the `PATH` environment variable when //! requested to start an executable at a non-absolute path. If `false`, -//! `posix_spawn()`, which does not consult `PATH`, will be used. If `true`, -//! `posix_spawnp()`, which does consult `PATH`, will be used. +//! `execv()`, which does not consult `PATH`, will be used. If `true`, +//! `execvp()`, which does consult `PATH`, will be used. //! \param[in] child_function If not `nullptr`, this function will be called in -//! the intermediate child process, prior to the `posix_spawn()`. Take note +//! the intermediate child process, prior to the second `fork()`. Take note //! that this function will run in the context of a forked process, and must //! be safe for that purpose. //! +//! Setting both \a envp to a value other than `nullptr` and \a use_path to +//! `true` is not currently supported. +//! //! \return `true` on success, and `false` on failure with a message logged. //! Only failures that occur in the parent process that indicate a definite //! failure to start the the grandchild are reported in the return value. @@ -60,12 +63,12 @@ namespace crashpad { //! terminating. The caller assumes the responsibility for detecting such //! failures, for example, by observing a failure to perform a successful //! handshake with the grandchild process. -bool ForkAndSpawn(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()); +bool DoubleForkAndExec(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()); } // namespace crashpad -#endif // CRASHPAD_UTIL_POSIX_FORK_AND_SPAWN_H_ +#endif // CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ diff --git a/util/posix/fork_and_spawn.cc b/util/posix/fork_and_spawn.cc deleted file mode 100644 index c6a95bbfdc..0000000000 --- a/util/posix/fork_and_spawn.cc +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2017 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "util/posix/fork_and_spawn.h" - -#include -#include -#include -#include -#include -#include - -#include "base/check.h" -#include "base/check_op.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/stringprintf.h" -#include "build/build_config.h" -#include "util/posix/close_multiple.h" - -extern char** environ; - -namespace crashpad { - -namespace { - -#if BUILDFLAG(IS_APPLE) - -class PosixSpawnAttr { - public: - PosixSpawnAttr() { - PCHECK((errno = posix_spawnattr_init(&attr_)) == 0) - << "posix_spawnattr_init"; - } - - PosixSpawnAttr(const PosixSpawnAttr&) = delete; - PosixSpawnAttr& operator=(const PosixSpawnAttr&) = delete; - - ~PosixSpawnAttr() { - PCHECK((errno = posix_spawnattr_destroy(&attr_)) == 0) - << "posix_spawnattr_destroy"; - } - - void SetFlags(short flags) { - PCHECK((errno = posix_spawnattr_setflags(&attr_, flags)) == 0) - << "posix_spawnattr_setflags"; - } - - const posix_spawnattr_t* Get() const { return &attr_; } - - private: - posix_spawnattr_t attr_; -}; - -class PosixSpawnFileActions { - public: - PosixSpawnFileActions() { - PCHECK((errno = posix_spawn_file_actions_init(&file_actions_)) == 0) - << "posix_spawn_file_actions_init"; - } - - PosixSpawnFileActions(const PosixSpawnFileActions&) = delete; - PosixSpawnFileActions& operator=(const PosixSpawnFileActions&) = delete; - - ~PosixSpawnFileActions() { - PCHECK((errno = posix_spawn_file_actions_destroy(&file_actions_)) == 0) - << "posix_spawn_file_actions_destroy"; - } - - void AddInheritedFileDescriptor(int fd) { - PCHECK((errno = posix_spawn_file_actions_addinherit_np(&file_actions_, - fd)) == 0) - << "posix_spawn_file_actions_addinherit_np"; - } - - const posix_spawn_file_actions_t* Get() const { return &file_actions_; } - - private: - posix_spawn_file_actions_t file_actions_; -}; - -#endif - -} // namespace - -bool ForkAndSpawn(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()) { - // argv_c contains const char* pointers and is terminated by nullptr. This is - // suitable for passing to posix_spawn() or posix_spawnp(). Although argv_c is - // not used in the parent process, it must be built in the parent process - // because it’s unsafe to do so in the child. - std::vector argv_c; - argv_c.reserve(argv.size() + 1); - for (const std::string& argument : argv) { - argv_c.push_back(argument.c_str()); - } - argv_c.push_back(nullptr); - - std::vector envp_c; - if (envp) { - envp_c.reserve(envp->size() + 1); - for (const std::string& variable : *envp) { - envp_c.push_back(variable.c_str()); - } - envp_c.push_back(nullptr); - } - - // The three processes involved are parent, child, and grandchild. The child - // exits immediately after spawning the grandchild, so the grandchild becomes - // an orphan and its parent process ID becomes 1. This relieves the parent and - // child of the responsibility to reap the grandchild with waitpid() or - // similar. The grandchild is expected to outlive the parent process, so the - // parent shouldn’t be concerned with reaping it. This approach means that - // accidental early termination of the handler process will not result in a - // zombie process. - pid_t pid = fork(); - if (pid < 0) { - PLOG(ERROR) << "fork"; - return false; - } - - if (pid == 0) { - // Child process. - - if (child_function) { - child_function(); - } - - // Call setsid(), creating a new process group and a new session, both led - // by this process. The new process group has no controlling terminal. This - // disconnects it from signals generated by the parent process’ terminal. - // - // setsid() is done in the child instead of the grandchild so that the - // grandchild will not be a session leader. If it were a session leader, an - // accidental open() of a terminal device without O_NOCTTY would make that - // terminal the controlling terminal. - // - // It’s not desirable for the grandchild to have a controlling terminal. The - // grandchild manages its own lifetime, such as by monitoring clients on its - // own and exiting when it loses all clients and when it deems it - // appropraite to do so. It may serve clients in different process groups or - // sessions than its original client, and receiving signals intended for its - // original client’s process group could be harmful in that case. - PCHECK(setsid() != -1) << "setsid"; - - // &argv_c[0] is a pointer to a pointer to const char data, but because of - // how C (not C++) works, posix_spawn() and posix_spawnp() want a pointer to - // a const pointer to char data. They modifies neither the data nor the - // pointers, so the const_cast is safe. - char* const* argv_for_spawn = const_cast(argv_c.data()); - - // This cast is safe for the same reason that the argv_for_spawn cast is. - char* const* envp_for_spawn = - envp ? const_cast(envp_c.data()) : environ; - -#if BUILDFLAG(IS_APPLE) - PosixSpawnAttr attr; - attr.SetFlags(POSIX_SPAWN_CLOEXEC_DEFAULT); - - PosixSpawnFileActions file_actions; - for (int fd = 0; fd <= STDERR_FILENO; ++fd) { - file_actions.AddInheritedFileDescriptor(fd); - } - file_actions.AddInheritedFileDescriptor(preserve_fd); - - const posix_spawnattr_t* attr_p = attr.Get(); - const posix_spawn_file_actions_t* file_actions_p = file_actions.Get(); -#else - CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); - - const posix_spawnattr_t* attr_p = nullptr; - const posix_spawn_file_actions_t* file_actions_p = nullptr; -#endif - - auto posix_spawn_fp = use_path ? posix_spawnp : posix_spawn; - if ((errno = posix_spawn_fp(&pid, - argv_for_spawn[0], - file_actions_p, - attr_p, - argv_for_spawn, - envp_for_spawn)) != 0) { - PLOG(FATAL) << (use_path ? "posix_spawnp" : "posix_spawn"); - } - - // _exit() instead of exit(), because fork() was called. - _exit(EXIT_SUCCESS); - } - - // waitpid() for the child, so that it does not become a zombie process. The - // child normally exits quickly. - // - // Failures from this point on may result in the accumulation of a zombie, but - // should not be considered fatal. Log only warnings, but don’t treat these - // failures as a failure of the function overall. - int status; - pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); - if (wait_pid == -1) { - PLOG(WARNING) << "waitpid"; - return true; - } - DCHECK_EQ(wait_pid, pid); - - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); - LOG(WARNING) << base::StringPrintf( - "intermediate process terminated by signal %d (%s)%s", - sig, - strsignal(sig), - WCOREDUMP(status) ? " (core dumped)" : ""); - } else if (!WIFEXITED(status)) { - LOG(WARNING) << base::StringPrintf( - "intermediate process: unknown termination 0x%x", status); - } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { - LOG(WARNING) << "intermediate process exited with code " - << WEXITSTATUS(status); - } - - return true; -} - -} // namespace crashpad From 1c37daa5acd500633cdffc7f6db61d8c6b32b771 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Fri, 24 Jun 2022 19:20:54 +0530 Subject: [PATCH 197/478] Reland "posix: Replace DoubleForkAndExec() with ForkAndSpawn()" This is a reland of 460943dd9a71dc76f68182a8ede766d5543e5341 Original change's description: > The DoubleForkAndExec() function was taking over 622 milliseconds to run > on macOS 11 (BigSur) on Intel i5-1038NG7. I did some debugging by adding > some custom traces and found that the fork() syscall is the bottleneck > here, i.e., the first fork() takes around 359 milliseconds and the > nested fork() takes around 263 milliseconds. Replacing the nested fork() > and exec() with posix_spawn() reduces the time consumption to 257 > milliseconds! > > See https://github.com/libuv/libuv/pull/3064 to know why fork() is so > slow on macOS and why posix_spawn() is a better replacement. > > Another point to note is that even base::LaunchProcess() from Chromium > calls posix_spawnp() on macOS - > https://source.chromium.org/chromium/chromium/src/+/8f8d82dea0fa8f11f57c74dbb65126f8daba58f7:base/process/launch_mac.cc;l=295-296 The reland isolates the change to non-Android POSIX systems because posix_spawn and posix_spawnp are available in Android NDK 28, but Chromium is building with version 23. Change-Id: If44629f5445bb0e3d0a1d3698b85f047d1cbf04f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3721655 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- AUTHORS | 1 + client/crashpad_client_linux.cc | 10 +- client/crashpad_client_mac.cc | 4 +- .../cros_crash_report_exception_handler.cc | 13 +- util/BUILD.gn | 4 +- util/posix/double_fork_and_exec.cc | 166 ----------- util/posix/spawn_subprocess.cc | 261 ++++++++++++++++++ ...ble_fork_and_exec.h => spawn_subprocess.h} | 57 ++-- 8 files changed, 303 insertions(+), 213 deletions(-) delete mode 100644 util/posix/double_fork_and_exec.cc create mode 100644 util/posix/spawn_subprocess.cc rename util/posix/{double_fork_and_exec.h => spawn_subprocess.h} (53%) diff --git a/AUTHORS b/AUTHORS index 8dcac32388..0210392433 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,3 +12,4 @@ Opera Software ASA Vewd Software AS LG Electronics, Inc. MIPS Technologies, Inc. +Darshan Sen diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 295ec1615d..9cd452b577 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -45,9 +45,9 @@ #include "util/linux/socket.h" #include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" -#include "util/posix/double_fork_and_exec.h" #include "util/posix/scoped_mmap.h" #include "util/posix/signals.h" +#include "util/posix/spawn_subprocess.h" namespace crashpad { @@ -459,7 +459,7 @@ bool CrashpadClient::StartHandler( argv.push_back(FormatArgumentInt("initial-client-fd", handler_sock.get())); argv.push_back("--shared-client-connection"); - if (!DoubleForkAndExec(argv, nullptr, handler_sock.get(), false, nullptr)) { + if (!SpawnSubprocess(argv, nullptr, handler_sock.get(), false, nullptr)) { return false; } @@ -614,7 +614,7 @@ bool CrashpadClient::StartJavaHandlerForClient( int socket) { std::vector argv = BuildAppProcessArgs( class_name, database, metrics_dir, url, annotations, arguments, socket); - return DoubleForkAndExec(argv, env, socket, false, nullptr); + return SpawnSubprocess(argv, env, socket, false, nullptr); } bool CrashpadClient::StartHandlerWithLinkerAtCrash( @@ -663,7 +663,7 @@ bool CrashpadClient::StartHandlerWithLinkerForClient( annotations, arguments, socket); - return DoubleForkAndExec(argv, env, socket, false, nullptr); + return SpawnSubprocess(argv, env, socket, false, nullptr); } #endif @@ -697,7 +697,7 @@ bool CrashpadClient::StartHandlerForClient( argv.push_back(FormatArgumentInt("initial-client-fd", socket)); - return DoubleForkAndExec(argv, nullptr, socket, true, nullptr); + return SpawnSubprocess(argv, nullptr, socket, true, nullptr); } // static diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index d25bfb7163..7e92cb86fd 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -36,7 +36,7 @@ #include "util/mach/notify_server.h" #include "util/misc/clock.h" #include "util/misc/implicit_cast.h" -#include "util/posix/double_fork_and_exec.h" +#include "util/posix/spawn_subprocess.h" namespace crashpad { @@ -343,7 +343,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { // this parent process, which was probably using the exception server now // being restarted. The handler can’t monitor itself for its own crashes via // this interface. - if (!DoubleForkAndExec( + if (!SpawnSubprocess( argv, nullptr, server_write_fd.get(), diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index 9e58d94aa4..4804eacf85 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -29,7 +29,7 @@ #include "util/linux/ptrace_client.h" #include "util/misc/metrics.h" #include "util/misc/uuid.h" -#include "util/posix/double_fork_and_exec.h" +#include "util/posix/spawn_subprocess.h" namespace crashpad { @@ -266,12 +266,11 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( argv.push_back("--always_allow_feedback"); } - if (!DoubleForkAndExec(argv, - nullptr /* envp */, - file_writer.fd() /* preserve_fd */, - false /* use_path */, - nullptr /* child_function */)) { - LOG(ERROR) << "DoubleForkAndExec failed"; + if (!SpawnSubprocess(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return false; diff --git a/util/BUILD.gn b/util/BUILD.gn index 3fe82c395e..6e6a8eec00 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -288,11 +288,11 @@ crashpad_static_library("util") { sources += [ "posix/close_multiple.cc", "posix/close_multiple.h", - "posix/double_fork_and_exec.cc", - "posix/double_fork_and_exec.h", "posix/drop_privileges.cc", "posix/drop_privileges.h", "posix/process_info.h", + "posix/spawn_subprocess.cc", + "posix/spawn_subprocess.h", # These map signals to and from strings. While Fuchsia defines some of # the common SIGx defines, signals are never raised on Fuchsia, so diff --git a/util/posix/double_fork_and_exec.cc b/util/posix/double_fork_and_exec.cc deleted file mode 100644 index 1960430954..0000000000 --- a/util/posix/double_fork_and_exec.cc +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2017 The Crashpad Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "util/posix/double_fork_and_exec.h" - -#include -#include -#include -#include - -#include "base/check_op.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/stringprintf.h" -#include "util/posix/close_multiple.h" - -namespace crashpad { - -bool DoubleForkAndExec(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()) { - DCHECK(!envp || !use_path); - - // argv_c contains const char* pointers and is terminated by nullptr. This is - // suitable for passing to execv(). Although argv_c is not used in the parent - // process, it must be built in the parent process because it’s unsafe to do - // so in the child or grandchild process. - std::vector argv_c; - argv_c.reserve(argv.size() + 1); - for (const std::string& argument : argv) { - argv_c.push_back(argument.c_str()); - } - argv_c.push_back(nullptr); - - std::vector envp_c; - if (envp) { - envp_c.reserve(envp->size() + 1); - for (const std::string& variable : *envp) { - envp_c.push_back(variable.c_str()); - } - envp_c.push_back(nullptr); - } - - // Double-fork(). The three processes involved are parent, child, and - // grandchild. The grandchild will call execv(). The child exits immediately - // after spawning the grandchild, so the grandchild becomes an orphan and its - // parent process ID becomes 1. This relieves the parent and child of the - // responsibility to reap the grandchild with waitpid() or similar. The - // grandchild is expected to outlive the parent process, so the parent - // shouldn’t be concerned with reaping it. This approach means that accidental - // early termination of the handler process will not result in a zombie - // process. - pid_t pid = fork(); - if (pid < 0) { - PLOG(ERROR) << "fork"; - return false; - } - - if (pid == 0) { - // Child process. - - if (child_function) { - child_function(); - } - - // Call setsid(), creating a new process group and a new session, both led - // by this process. The new process group has no controlling terminal. This - // disconnects it from signals generated by the parent process’ terminal. - // - // setsid() is done in the child instead of the grandchild so that the - // grandchild will not be a session leader. If it were a session leader, an - // accidental open() of a terminal device without O_NOCTTY would make that - // terminal the controlling terminal. - // - // It’s not desirable for the grandchild to have a controlling terminal. The - // grandchild manages its own lifetime, such as by monitoring clients on its - // own and exiting when it loses all clients and when it deems it - // appropraite to do so. It may serve clients in different process groups or - // sessions than its original client, and receiving signals intended for its - // original client’s process group could be harmful in that case. - PCHECK(setsid() != -1) << "setsid"; - - pid = fork(); - if (pid < 0) { - PLOG(FATAL) << "fork"; - } - - if (pid > 0) { - // Child process. - - // _exit() instead of exit(), because fork() was called. - _exit(EXIT_SUCCESS); - } - - // Grandchild process. - - CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); - - // &argv_c[0] is a pointer to a pointer to const char data, but because of - // how C (not C++) works, execvp() wants a pointer to a const pointer to - // char data. It modifies neither the data nor the pointers, so the - // const_cast is safe. - char* const* argv_for_execv = const_cast(&argv_c[0]); - - if (envp) { - // This cast is safe for the same reason that the argv_for_execv cast is. - char* const* envp_for_execv = const_cast(&envp_c[0]); - execve(argv_for_execv[0], argv_for_execv, envp_for_execv); - PLOG(FATAL) << "execve " << argv_for_execv[0]; - } - - if (use_path) { - execvp(argv_for_execv[0], argv_for_execv); - PLOG(FATAL) << "execvp " << argv_for_execv[0]; - } - - execv(argv_for_execv[0], argv_for_execv); - PLOG(FATAL) << "execv " << argv_for_execv[0]; - } - - // waitpid() for the child, so that it does not become a zombie process. The - // child normally exits quickly. - // - // Failures from this point on may result in the accumulation of a zombie, but - // should not be considered fatal. Log only warnings, but don’t treat these - // failures as a failure of the function overall. - int status; - pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); - if (wait_pid == -1) { - PLOG(WARNING) << "waitpid"; - return true; - } - DCHECK_EQ(wait_pid, pid); - - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); - LOG(WARNING) << base::StringPrintf( - "intermediate process terminated by signal %d (%s)%s", - sig, - strsignal(sig), - WCOREDUMP(status) ? " (core dumped)" : ""); - } else if (!WIFEXITED(status)) { - LOG(WARNING) << base::StringPrintf( - "intermediate process: unknown termination 0x%x", status); - } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { - LOG(WARNING) << "intermediate process exited with code " - << WEXITSTATUS(status); - } - - return true; -} - -} // namespace crashpad diff --git a/util/posix/spawn_subprocess.cc b/util/posix/spawn_subprocess.cc new file mode 100644 index 0000000000..43fca18deb --- /dev/null +++ b/util/posix/spawn_subprocess.cc @@ -0,0 +1,261 @@ +// Copyright 2017 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/posix/spawn_subprocess.h" + +#include +#include +#include +#include +#include +#include + +#include "base/check.h" +#include "base/check_op.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "util/posix/close_multiple.h" + +#if BUILDFLAG(IS_ANDROID) +#include +#endif + +extern char** environ; + +namespace crashpad { + +namespace { + +#if BUILDFLAG(IS_APPLE) + +class PosixSpawnAttr { + public: + PosixSpawnAttr() { + PCHECK((errno = posix_spawnattr_init(&attr_)) == 0) + << "posix_spawnattr_init"; + } + + PosixSpawnAttr(const PosixSpawnAttr&) = delete; + PosixSpawnAttr& operator=(const PosixSpawnAttr&) = delete; + + ~PosixSpawnAttr() { + PCHECK((errno = posix_spawnattr_destroy(&attr_)) == 0) + << "posix_spawnattr_destroy"; + } + + void SetFlags(short flags) { + PCHECK((errno = posix_spawnattr_setflags(&attr_, flags)) == 0) + << "posix_spawnattr_setflags"; + } + + const posix_spawnattr_t* Get() const { return &attr_; } + + private: + posix_spawnattr_t attr_; +}; + +class PosixSpawnFileActions { + public: + PosixSpawnFileActions() { + PCHECK((errno = posix_spawn_file_actions_init(&file_actions_)) == 0) + << "posix_spawn_file_actions_init"; + } + + PosixSpawnFileActions(const PosixSpawnFileActions&) = delete; + PosixSpawnFileActions& operator=(const PosixSpawnFileActions&) = delete; + + ~PosixSpawnFileActions() { + PCHECK((errno = posix_spawn_file_actions_destroy(&file_actions_)) == 0) + << "posix_spawn_file_actions_destroy"; + } + + void AddInheritedFileDescriptor(int fd) { + PCHECK((errno = posix_spawn_file_actions_addinherit_np(&file_actions_, + fd)) == 0) + << "posix_spawn_file_actions_addinherit_np"; + } + + const posix_spawn_file_actions_t* Get() const { return &file_actions_; } + + private: + posix_spawn_file_actions_t file_actions_; +}; + +#endif + +} // namespace + +bool SpawnSubprocess(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()) { + // argv_c contains const char* pointers and is terminated by nullptr. This is + // suitable for passing to posix_spawn*() and execv*(). Although argv_c is not + // used in the parent process, it must be built in the parent process because + // it’s unsafe to do so in the child or grandchild process. + std::vector argv_c; + argv_c.reserve(argv.size() + 1); + for (const std::string& argument : argv) { + argv_c.push_back(argument.c_str()); + } + argv_c.push_back(nullptr); + + std::vector envp_c; + if (envp) { + envp_c.reserve(envp->size() + 1); + for (const std::string& variable : *envp) { + envp_c.push_back(variable.c_str()); + } + envp_c.push_back(nullptr); + } + + // The three processes involved are parent, child, and grandchild. The child + // exits immediately after spawning the grandchild, so the grandchild becomes + // an orphan and its parent process ID becomes 1. This relieves the parent and + // child of the responsibility to reap the grandchild with waitpid() or + // similar. The grandchild is expected to outlive the parent process, so the + // parent shouldn’t be concerned with reaping it. This approach means that + // accidental early termination of the handler process will not result in a + // zombie process. + pid_t pid = fork(); + if (pid < 0) { + PLOG(ERROR) << "fork"; + return false; + } + + if (pid == 0) { + // Child process. + + if (child_function) { + child_function(); + } + + // Call setsid(), creating a new process group and a new session, both led + // by this process. The new process group has no controlling terminal. This + // disconnects it from signals generated by the parent process’ terminal. + // + // setsid() is done in the child instead of the grandchild so that the + // grandchild will not be a session leader. If it were a session leader, an + // accidental open() of a terminal device without O_NOCTTY would make that + // terminal the controlling terminal. + // + // It’s not desirable for the grandchild to have a controlling terminal. The + // grandchild manages its own lifetime, such as by monitoring clients on its + // own and exiting when it loses all clients and when it deems it + // appropraite to do so. It may serve clients in different process groups or + // sessions than its original client, and receiving signals intended for its + // original client’s process group could be harmful in that case. + PCHECK(setsid() != -1) << "setsid"; + + // &argv_c[0] is a pointer to a pointer to const char data, but because of + // how C (not C++) works, posix_spawn*() and execv*() want a pointer to + // a const pointer to char data. They modify neither the data nor the + // pointers, so the const_cast is safe. + char* const* argv_for_spawn = const_cast(argv_c.data()); + + // This cast is safe for the same reason that the argv_for_spawn cast is. + char* const* envp_for_spawn = + envp ? const_cast(envp_c.data()) : environ; + +#if BUILDFLAG(IS_ANDROID) && __ANDROID_API__ < 28 + pid = fork(); + if (pid < 0) { + PLOG(FATAL) << "fork"; + } + + if (pid > 0) { + // Child process. + + // _exit() instead of exit(), because fork() was called. + _exit(EXIT_SUCCESS); + } + + // Grandchild process. + + CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); + + auto execve_fp = use_path ? execvpe : execve; + execve_fp(argv_for_spawn[0], argv_for_spawn, envp_for_spawn); + PLOG(FATAL) << (use_path ? "execvpe" : "execve"); +#else +#if BUILDFLAG(IS_APPLE) + PosixSpawnAttr attr; + attr.SetFlags(POSIX_SPAWN_CLOEXEC_DEFAULT); + + PosixSpawnFileActions file_actions; + for (int fd = 0; fd <= STDERR_FILENO; ++fd) { + file_actions.AddInheritedFileDescriptor(fd); + } + file_actions.AddInheritedFileDescriptor(preserve_fd); + + const posix_spawnattr_t* attr_p = attr.Get(); + const posix_spawn_file_actions_t* file_actions_p = file_actions.Get(); +#else + CloseMultipleNowOrOnExec(STDERR_FILENO + 1, preserve_fd); + + const posix_spawnattr_t* attr_p = nullptr; + const posix_spawn_file_actions_t* file_actions_p = nullptr; +#endif + + auto posix_spawn_fp = use_path ? posix_spawnp : posix_spawn; + if ((errno = posix_spawn_fp(nullptr, + argv_for_spawn[0], + file_actions_p, + attr_p, + argv_for_spawn, + envp_for_spawn)) != 0) { + PLOG(FATAL) << (use_path ? "posix_spawnp" : "posix_spawn"); + } + + // _exit() instead of exit(), because fork() was called. + _exit(EXIT_SUCCESS); +#endif + } + + // waitpid() for the child, so that it does not become a zombie process. The + // child normally exits quickly. + // + // Failures from this point on may result in the accumulation of a zombie, but + // should not be considered fatal. Log only warnings, but don’t treat these + // failures as a failure of the function overall. + int status; + pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); + if (wait_pid == -1) { + PLOG(WARNING) << "waitpid"; + return true; + } + DCHECK_EQ(wait_pid, pid); + + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + LOG(WARNING) << base::StringPrintf( + "intermediate process terminated by signal %d (%s)%s", + sig, + strsignal(sig), + WCOREDUMP(status) ? " (core dumped)" : ""); + } else if (!WIFEXITED(status)) { + LOG(WARNING) << base::StringPrintf( + "intermediate process: unknown termination 0x%x", status); + } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { + LOG(WARNING) << "intermediate process exited with code " + << WEXITSTATUS(status); + } + + return true; +} + +} // namespace crashpad diff --git a/util/posix/double_fork_and_exec.h b/util/posix/spawn_subprocess.h similarity index 53% rename from util/posix/double_fork_and_exec.h rename to util/posix/spawn_subprocess.h index 02fc0f28f1..23910810b1 100644 --- a/util/posix/double_fork_and_exec.h +++ b/util/posix/spawn_subprocess.h @@ -12,48 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ -#define CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ +#ifndef CRASHPAD_UTIL_POSIX_SPAWN_SUBPROCESS_H_ +#define CRASHPAD_UTIL_POSIX_SPAWN_SUBPROCESS_H_ #include #include namespace crashpad { -//! \brief Executes a (grand-)child process. +//! \brief Spawns a subprocess. //! -//! The grandchild process will be started through the -//! double-`fork()`-and-`execv()` pattern. This allows the grandchild to fully -//! disassociate from the parent. The grandchild will not be a member of the -//! parent’s process group or session and will not have a controlling terminal, -//! providing isolation from signals not intended for it. The grandchild’s -//! parent process, in terms of the process tree hierarchy, will be the process -//! with process ID 1, relieving any other process of the responsibility to reap -//! it via `waitpid()`. Aside from the three file descriptors associated with -//! the standard input/output streams and any file descriptor passed in \a -//! preserve_fd, the grandchild will not inherit any file descriptors from the -//! parent process. +//! A grandchild process will be started through the +//! `fork()`-and-`posix_spawn()` pattern where supported, and +//! double-`fork()`-and-`execv()` pattern elsewhere. This allows the grandchild +//! to fully disassociate from the parent. The grandchild will not be a member +//! of the parent’s process group or session and will not have a controlling +//! terminal, providing isolation from signals not intended for it. The +//! grandchild’s parent process, in terms of the process tree hierarchy, will be +//! the process with process ID 1, relieving any other process of the +//! responsibility to reap it via `waitpid()`. Aside from the three file +//! descriptors associated with the standard input/output streams and any file +//! descriptor passed in \a preserve_fd, the grandchild will not inherit any +//! file descriptors from the parent process. //! //! \param[in] argv The argument vector to start the grandchild process with. //! `argv[0]` is used as the path to the executable. //! \param[in] envp A vector of environment variables of the form `var=value` to -//! be passed to `execve()`. If this value is `nullptr`, the current -//! environment is used. +//! be passed to the spawned process. If this value is `nullptr`, the +//! current environment is used. //! \param[in] preserve_fd A file descriptor to be inherited by the grandchild //! process. This file descriptor is inherited in addition to the three file //! descriptors associated with the standard input/output streams. Use `-1` //! if no additional file descriptors are to be inherited. //! \param[in] use_path Whether to consult the `PATH` environment variable when -//! requested to start an executable at a non-absolute path. If `false`, -//! `execv()`, which does not consult `PATH`, will be used. If `true`, -//! `execvp()`, which does consult `PATH`, will be used. +//! requested to start an executable at a non-absolute path. //! \param[in] child_function If not `nullptr`, this function will be called in -//! the intermediate child process, prior to the second `fork()`. Take note -//! that this function will run in the context of a forked process, and must -//! be safe for that purpose. -//! -//! Setting both \a envp to a value other than `nullptr` and \a use_path to -//! `true` is not currently supported. +//! the intermediate child process. Take note that this function will run in +//! the context of a forked process, and must be safe for that purpose. //! //! \return `true` on success, and `false` on failure with a message logged. //! Only failures that occur in the parent process that indicate a definite @@ -63,12 +58,12 @@ namespace crashpad { //! terminating. The caller assumes the responsibility for detecting such //! failures, for example, by observing a failure to perform a successful //! handshake with the grandchild process. -bool DoubleForkAndExec(const std::vector& argv, - const std::vector* envp, - int preserve_fd, - bool use_path, - void (*child_function)()); +bool SpawnSubprocess(const std::vector& argv, + const std::vector* envp, + int preserve_fd, + bool use_path, + void (*child_function)()); } // namespace crashpad -#endif // CRASHPAD_UTIL_POSIX_DOUBLE_FORK_AND_EXEC_H_ +#endif // CRASHPAD_UTIL_POSIX_SPAWN_SUBPROCESS_H_ From 80f383327eb5c55bc11d5d1d4917bd00a860871b Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 27 Jun 2022 12:36:34 -0400 Subject: [PATCH 198/478] [win] Fix ScopedSetThreadName for Windows 7 Windows 7 doesn't support SetThreadDescription/GetThreadDescription. Add an IsSupported to ScopedSetThreadName test to wrap unsupported calls. Change-Id: I70d4e20b94efea03e41c5f7ed8d8e1b886192923 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3722556 Commit-Queue: Justin Cohen Reviewed-by: Mark Mentovai --- snapshot/win/process_reader_win_test.cc | 43 ++++++++++++---------- test/scoped_set_thread_name.h | 7 +++- test/scoped_set_thread_name_win.cc | 48 +++++++++++++++++++------ 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 98cb11b7af..2ff9f1146d 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -123,7 +123,9 @@ TEST(ProcessReaderWin, SelfOneThread) { ASSERT_GE(threads.size(), 1u); EXPECT_EQ(threads[0].id, GetCurrentThreadId()); - EXPECT_EQ(threads[0].name, "SelfBasic"); + if (ScopedSetThreadName::IsSupported()) { + EXPECT_EQ(threads[0].name, "SelfBasic"); + } EXPECT_NE(ProgramCounterFromCONTEXT(threads[0].context.context()), nullptr); EXPECT_EQ(threads[0].suspend_count, 0u); @@ -174,28 +176,31 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { const auto& threads = process_reader.Threads(); ASSERT_GE(threads.size(), kCreatedThreads + 1); - EXPECT_EQ(threads[0].name, "WinMultiprocessChild-Main"); - - const std::set expected_thread_names = { - "WinMultiprocessChild-1", - "WinMultiprocessChild-2", - "WinMultiprocessChild-3", - }; - // Windows can create threads besides the ones created in - // WinMultiprocessChild(), so keep track of the (non-main) thread names - // and make sure all the expected names are present. - std::set thread_names; - for (size_t i = 1; i < threads.size(); i++) { - if (!threads[i].name.empty()) { - thread_names.emplace(threads[i].name); - } - } - - EXPECT_THAT(thread_names, IsSupersetOf(expected_thread_names)); for (const auto& thread : threads) { EXPECT_EQ(thread.suspend_count, 0u); } + + if (ScopedSetThreadName::IsSupported()) { + EXPECT_EQ(threads[0].name, "WinMultiprocessChild-Main"); + + const std::set expected_thread_names = { + "WinMultiprocessChild-1", + "WinMultiprocessChild-2", + "WinMultiprocessChild-3", + }; + // Windows can create threads besides the ones created in + // WinMultiprocessChild(), so keep track of the (non-main) thread names + // and make sure all the expected names are present. + std::set thread_names; + for (size_t i = 1; i < threads.size(); i++) { + if (!threads[i].name.empty()) { + thread_names.emplace(threads[i].name); + } + } + + EXPECT_THAT(thread_names, IsSupersetOf(expected_thread_names)); + } } { diff --git a/test/scoped_set_thread_name.h b/test/scoped_set_thread_name.h index 69998c03b9..dc149e4f15 100644 --- a/test/scoped_set_thread_name.h +++ b/test/scoped_set_thread_name.h @@ -32,9 +32,14 @@ class ScopedSetThreadName final { ~ScopedSetThreadName(); +#if BUILDFLAG(IS_WIN) || DOXYGEN + //! \brief Returns `true` if Windows supports setting and getting thread name. + static bool IsSupported(); +#endif + private: #if BUILDFLAG(IS_WIN) - const std::wstring original_name_; + std::wstring original_name_; #else const std::string original_name_; #endif diff --git a/test/scoped_set_thread_name_win.cc b/test/scoped_set_thread_name_win.cc index 482d3c12e5..37c87ee86c 100644 --- a/test/scoped_set_thread_name_win.cc +++ b/test/scoped_set_thread_name_win.cc @@ -19,6 +19,7 @@ #include "base/check.h" #include "base/logging.h" #include "base/strings/utf_string_conversions.h" +#include "util/win/get_function.h" #include "util/win/scoped_local_alloc.h" namespace crashpad { @@ -26,30 +27,57 @@ namespace test { namespace { +auto GetThreadDescriptionFuncPtr() { + static const auto get_thread_description = + GET_FUNCTION(L"kernel32.dll", ::GetThreadDescription); + return get_thread_description; +} + +auto SetThreadDescriptionFuncPtr() { + static const auto set_thread_description = + GET_FUNCTION(L"kernel32.dll", ::SetThreadDescription); + return set_thread_description; +} + std::wstring GetCurrentThreadName() { wchar_t* thread_description; - HRESULT hr = GetThreadDescription(GetCurrentThread(), &thread_description); + const auto get_thread_description = GetThreadDescriptionFuncPtr(); + DCHECK(get_thread_description); + HRESULT hr = get_thread_description(GetCurrentThread(), &thread_description); CHECK(SUCCEEDED(hr)) << "GetThreadDescription: " << logging::SystemErrorCodeToString(hr); ScopedLocalAlloc thread_description_owner(thread_description); return std::wstring(thread_description); } -} // namespace - -ScopedSetThreadName::ScopedSetThreadName(const std::string& new_thread_name) - : original_name_(GetCurrentThreadName()) { - const std::wstring wnew_thread_name = base::UTF8ToWide(new_thread_name); +void SetCurrentThreadName(const std::wstring& new_thread_name) { + const auto set_thread_description = SetThreadDescriptionFuncPtr(); + DCHECK(set_thread_description); HRESULT hr = - SetThreadDescription(GetCurrentThread(), wnew_thread_name.c_str()); + set_thread_description(GetCurrentThread(), new_thread_name.c_str()); CHECK(SUCCEEDED(hr)) << "SetThreadDescription: " << logging::SystemErrorCodeToString(hr); } +} // namespace + +ScopedSetThreadName::ScopedSetThreadName(const std::string& new_thread_name) + : original_name_() { + if (IsSupported()) { + original_name_.assign(GetCurrentThreadName()); + SetCurrentThreadName(base::UTF8ToWide(new_thread_name)); + } +} + ScopedSetThreadName::~ScopedSetThreadName() { - HRESULT hr = SetThreadDescription(GetCurrentThread(), original_name_.c_str()); - CHECK(SUCCEEDED(hr)) << "SetThreadDescription: " - << logging::SystemErrorCodeToString(hr); + if (IsSupported()) { + SetCurrentThreadName(original_name_); + } +} + +// static +bool ScopedSetThreadName::IsSupported() { + return GetThreadDescriptionFuncPtr() && SetThreadDescriptionFuncPtr(); } } // namespace test From bac699ef47cd7650575446d4a266d56f95097974 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 27 Jun 2022 14:00:13 -0400 Subject: [PATCH 199/478] ios: Correct xcode-hybrid setup for Xcode 14. Changes copied verbatim from Chromium with one exception to remove Chromium specific gn args. This includes a mini_chromium roll to not codesign within Xcode. Change-Id: I89b35bee08f9bc9e37f902f2b57e02acb2113ae1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3726509 Reviewed-by: Rohit Rao Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- DEPS | 2 +- build/ios/convert_gn_xcodeproj.py | 184 +++++++++++++----------- build/ios/setup_ios_gn.py | 11 +- build/ios/xcodescheme-testable.template | 63 ++++++++ build/ios/xcodescheme.template | 2 - 5 files changed, 166 insertions(+), 96 deletions(-) diff --git a/DEPS b/DEPS index 4a2012548c..0f29f6d024 100644 --- a/DEPS +++ b/DEPS @@ -44,7 +44,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '5654edb4225bcad13901155c819febb5748e502b', + '75dcb8dc417af77fdb9ec23c7b51cb1d57dfcee2', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py index 8c5c6d073f..2bce72d694 100755 --- a/build/ios/convert_gn_xcodeproj.py +++ b/build/ios/convert_gn_xcodeproj.py @@ -28,6 +28,7 @@ import filecmp import functools import hashlib +import io import json import os import re @@ -65,7 +66,7 @@ class Template(string.Template): @functools.lru_cache def LoadSchemeTemplate(root, name): """Return a string.Template object for scheme file loaded relative to root.""" - path = os.path.join(root, 'build', 'ios', name) + path = os.path.join(root, 'build', 'ios', name + '.template') with open(path) as file: return Template(file.read()) @@ -75,7 +76,7 @@ def CreateIdentifier(str_id): return hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper() -def GenerateSchemeForTarget(root, project, old_project, name, path, tests): +def GenerateSchemeForTarget(root, project, old_project, name, path, is_test): """Generates the .xcsheme file for target named |name|. The file is generated in the new project schemes directory from a template. @@ -91,9 +92,23 @@ def GenerateSchemeForTarget(root, project, old_project, name, path, tests): if not os.path.isdir(os.path.dirname(scheme_path)): os.makedirs(os.path.dirname(scheme_path)) + substitutions = { + 'LLDBINIT_PATH': LLDBINIT_PATH, + 'BLUEPRINT_IDENTIFIER': identifier, + 'BUILDABLE_NAME': path, + 'BLUEPRINT_NAME': name, + 'PROJECT_NAME': project_name + } + + if is_test: + template = LoadSchemeTemplate(root, 'xcodescheme-testable') + substitutions['PATH'] = os.environ['PATH'] + + else: + template = LoadSchemeTemplate(root, 'xcodescheme') + old_scheme_path = os.path.join(old_project, relative_path) if os.path.exists(old_scheme_path): - made_changes = False tree = xml.etree.ElementTree.parse(old_scheme_path) tree_root = tree.getroot() @@ -105,7 +120,6 @@ def GenerateSchemeForTarget(root, project, old_project, name, path, tests): ('BlueprintIdentifier', identifier)): if reference.get(attr) != value: reference.set(attr, value) - made_changes = True for child in tree_root: if child.tag not in ('TestAction', 'LaunchAction'): @@ -113,59 +127,29 @@ def GenerateSchemeForTarget(root, project, old_project, name, path, tests): if child.get('customLLDBInitFile') != LLDBINIT_PATH: child.set('customLLDBInitFile', LLDBINIT_PATH) - made_changes = True - # Override the list of testables. - if child.tag == 'TestAction': - for subchild in child: - if subchild.tag != 'Testables': - continue + if is_test: - for elt in list(subchild): - subchild.remove(elt) + template_tree = xml.etree.ElementTree.parse( + io.StringIO(template.substitute(**substitutions))) - if tests: - template = LoadSchemeTemplate(root, 'xcodescheme-testable.template') - for (key, test_path, test_name) in sorted(tests): - testable = ''.join(template.substitute( - BLUEPRINT_IDENTIFIER=key, - BUILDABLE_NAME=test_path, - BLUEPRINT_NAME=test_name, - PROJECT_NAME=project_name)) + template_tree_root = template_tree.getroot() + for child in tree_root: + if child.tag != 'BuildAction': + continue - testable_elt = xml.etree.ElementTree.fromstring(testable) - subchild.append(testable_elt) + for subchild in list(child): + child.remove(subchild) - if made_changes: - tree.write(scheme_path, xml_declaration=True, encoding='UTF-8') + for post_action in template_tree_root.findall('.//PostActions'): + child.append(post_action) - else: - shutil.copyfile(old_scheme_path, scheme_path) + tree.write(scheme_path, xml_declaration=True, encoding='UTF-8') else: - testables = '' - if tests: - template = LoadSchemeTemplate(root, 'xcodescheme-testable.template') - testables = '\n' + ''.join( - template.substitute( - BLUEPRINT_IDENTIFIER=key, - BUILDABLE_NAME=test_path, - BLUEPRINT_NAME=test_name, - PROJECT_NAME=project_name) - for (key, test_path, test_name) in sorted(tests)).rstrip() - - template = LoadSchemeTemplate(root, 'xcodescheme.template') - with open(scheme_path, 'w') as scheme_file: - scheme_file.write( - template.substitute( - TESTABLES=testables, - LLDBINIT_PATH=LLDBINIT_PATH, - BLUEPRINT_IDENTIFIER=identifier, - BUILDABLE_NAME=path, - BLUEPRINT_NAME=name, - PROJECT_NAME=project_name)) + scheme_file.write(template.substitute(**substitutions)) class XcodeProject(object): @@ -225,6 +209,7 @@ def UpdateBuildConfigurations(self, configurations): # because objects will be added to/removed from the project upon # iterating this list and python dictionaries cannot be mutated # during iteration. + for key, obj in list(self.IterObjectsByIsa('XCConfigurationList')): # Use the first build configuration as template for creating all the # new build configurations. @@ -232,7 +217,6 @@ def UpdateBuildConfigurations(self, configurations): build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \ '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)' - # Remove the existing build configurations from the project before # creating the new ones. for build_config_id in obj['buildConfigurations']: @@ -342,48 +326,56 @@ def UpdateXcodeProject(project_dir, old_project_dir, configurations, root_dir): product = project.objects[obj['productReference']] product_path = product['path'] - # For XCTests, the key is the product path, while for XCUITests, the key - # is the target name. Use a sum of both possible keys (there should not - # be overlaps since different hosts are used for XCTests and XCUITests - # but this make the code simpler). + # Do not generate scheme for the XCTests and XXCUITests target app. + # Instead, a scheme will be generated for each test modules. tests = mapping.get(product_path, []) + mapping.get(obj['name'], []) - GenerateSchemeForTarget( - root_dir, project_dir, old_project_dir, - obj['name'], product_path, tests) + if not tests: + GenerateSchemeForTarget( + root_dir, project_dir, old_project_dir, + obj['name'], product_path, False) + + else: + for (_, test_name, test_path) in tests: + GenerateSchemeForTarget( + root_dir, project_dir, old_project_dir, + test_name, test_path, True) + + root_object = project.objects[json_data['rootObject']] + main_group = project.objects[root_object['mainGroup']] + + sources = None + for child_key in main_group['children']: + child = project.objects[child_key] + if child.get('name') == 'Source' or child.get('name') == 'Sources': + sources = child + break + if sources is None: + sources = main_group - source = GetOrCreateRootGroup(project, json_data['rootObject'], 'Source') - AddMarkdownToProject(project, root_dir, source) - SortFileReferencesByName(project, source) + AddMarkdownToProject(project, root_dir, sources, sources is main_group) + SortFileReferencesByName(project, sources, root_object.get('productRefGroup')) objects = collections.OrderedDict(sorted(project.objects.items())) - WriteXcodeProject(project_dir, json.dumps(json_data)) + # WriteXcodeProject(project_dir, json.dumps(json_data)) -def CreateGroup(project, parent_group, group_name, path=None): +def CreateGroup(project, parent_group, group_name, use_relative_paths): group_object = { 'children': [], 'isa': 'PBXGroup', - 'name': group_name, 'sourceTree': '', } - if path is not None: - group_object['path'] = path + if use_relative_paths: + group_object['path'] = group_name + else: + group_object['name'] = group_name parent_group_name = parent_group.get('name', '') group_object_key = project.AddObject(parent_group_name, group_object) parent_group['children'].append(group_object_key) return group_object -def GetOrCreateRootGroup(project, root_object, group_name): - main_group = project.objects[project.objects[root_object]['mainGroup']] - for child_key in main_group['children']: - child = project.objects[child_key] - if child['name'] == group_name: - return child - return CreateGroup(project, main_group, group_name, path='../..') - - class ObjectKey(object): """Wrapper around PBXFileReference and PBXGroup for sorting. @@ -401,19 +393,24 @@ class ObjectKey(object): is checked and compared in alphabetic order. """ - def __init__(self, obj): + def __init__(self, obj, last): self.isa = obj['isa'] if 'name' in obj: self.name = obj['name'] else: self.name = obj['path'] + self.last = last def __lt__(self, other): + if self.last != other.last: + return other.last if self.isa != other.isa: return self.isa > other.isa return self.name < other.name def __gt__(self, other): + if self.last != other.last: + return self.last if self.isa != other.isa: return self.isa < other.isa return self.name > other.name @@ -422,9 +419,10 @@ def __eq__(self, other): return self.isa == other.isa and self.name == other.name -def SortFileReferencesByName(project, group_object): +def SortFileReferencesByName(project, group_object, products_group_ref): SortFileReferencesByNameWithSortKey( - project, group_object, lambda ref: ObjectKey(project.objects[ref])) + project, group_object, + lambda ref: ObjectKey(project.objects[ref], ref == products_group_ref)) def SortFileReferencesByNameWithSortKey(project, group_object, sort_key): @@ -435,7 +433,7 @@ def SortFileReferencesByNameWithSortKey(project, group_object, sort_key): SortFileReferencesByNameWithSortKey(project, child, sort_key) -def AddMarkdownToProject(project, root_dir, group_object): +def AddMarkdownToProject(project, root_dir, group_object, use_relative_paths): list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md'] paths = check_output(list_files_cmd).splitlines() ios_internal_dir = os.path.join(root_dir, 'ios_internal') @@ -448,31 +446,43 @@ def AddMarkdownToProject(project, root_dir, group_object): "fileEncoding": "4", "isa": "PBXFileReference", "lastKnownFileType": "net.daringfireball.markdown", - "name": os.path.basename(path), - "path": path, "sourceTree": "" } - new_markdown_entry_id = project.AddObject('sources', new_markdown_entry) - folder = GetFolderForPath(project, group_object, os.path.dirname(path)) + if use_relative_paths: + new_markdown_entry['path'] = os.path.basename(path) + else: + new_markdown_entry['name'] = os.path.basename(path) + new_markdown_entry['path'] = path + folder = GetFolderForPath( + project, group_object, os.path.dirname(path), + use_relative_paths) + folder_name = folder.get('name', None) + if folder_name is None: + folder_name = folder.get('path', 'sources') + new_markdown_entry_id = project.AddObject(folder_name, new_markdown_entry) folder['children'].append(new_markdown_entry_id) -def GetFolderForPath(project, group_object, path): +def GetFolderForPath(project, group_object, path, use_relative_paths): objects = project.objects if not path: return group_object for folder in path.split('/'): children = group_object['children'] new_root = None - for child in children: - if objects[child]['isa'] == 'PBXGroup' and \ - objects[child]['name'] == folder: - new_root = objects[child] - break + for child_key in children: + child = objects[child_key] + if child['isa'] == 'PBXGroup': + child_name = child.get('name', None) + if child_name is None: + child_name = child.get('path') + if child_name == folder: + new_root = child + break if not new_root: # If the folder isn't found we could just cram it into the leaf existing # folder, but that leads to folders with tons of README.md inside. - new_root = CreateGroup(project, group_object, folder) + new_root = CreateGroup(project, group_object, folder, use_relative_paths) group_object = new_root return group_object diff --git a/build/ios/setup_ios_gn.py b/build/ios/setup_ios_gn.py index aacc8ec7bd..333864eedf 100755 --- a/build/ios/setup_ios_gn.py +++ b/build/ios/setup_ios_gn.py @@ -110,7 +110,7 @@ def __init__(self, settings, config, target): self._config = config self._target = target - def _GetGnArgs(self, extra_args=None): + def _GetGnArgs(self): """Build the list of arguments to pass to gn. Returns: @@ -134,11 +134,6 @@ def _GetGnArgs(self, extra_args=None): 'target_environment', self.TARGET_ENVIRONMENT_VALUES[self._target])) - # If extra arguments are passed to the function, pass them before the - # user overrides (if any). - if extra_args is not None: - args.extend(extra_args) - # Add user overrides after the other configurations so that they can # refer to them and override them. args.extend(self._settings.items('gn_args')) @@ -218,6 +213,10 @@ def GetGnCommand(self, gn_path, src_path, out_path, xcode_project_name=None): gn_command.append('--ninja-executable=autoninja') gn_command.append('--xcode-build-system=new') gn_command.append('--xcode-project=%s' % xcode_project_name) + gn_command.append('--xcode-additional-files-patterns=*.md') + gn_command.append('--xcode-configs=' + ';'.join(SUPPORTED_CONFIGS)) + gn_command.append('--xcode-config-build-dir=' + '//out/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}') if self._settings.has_section('filters'): target_filters = self._settings.values('filters') if target_filters: diff --git a/build/ios/xcodescheme-testable.template b/build/ios/xcodescheme-testable.template index 61b6f471b7..24ba39a97d 100644 --- a/build/ios/xcodescheme-testable.template +++ b/build/ios/xcodescheme-testable.template @@ -1,3 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/ios/xcodescheme.template b/build/ios/xcodescheme.template index 514bea4ef0..b7cda4b10b 100644 --- a/build/ios/xcodescheme.template +++ b/build/ios/xcodescheme.template @@ -28,8 +28,6 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" customLLDBInitFile = "@{LLDBINIT_PATH}" shouldUseLaunchSchemeArgsEnv = "YES"> - @{TESTABLES} - Date: Wed, 6 Jul 2022 13:53:12 -0700 Subject: [PATCH 200/478] Add WER runtime exception helper module for Windows This adds a runtime exception helper (& test module) for Windows and plumbing to allow the module to be registered by the crashpad client, and to trigger the crashpad handler. Embedders can build their own module to control which exceptions are passed to the handler. See: go/chrome-windows-runtime-exception-helper for motivation. When registered (which is the responsibility of the embedding application), the helper is loaded by WerFault.exe when Windows Error Reporting receives crashes that are not caught by crashpad's normal handlers - for instance a control-flow violation when a module is compiled with /guard:cf. Registration: The embedder must arrange for the full path to the helper to be added in the appropriate Windows Error Reporting\ RuntimeExceptionHelperModules registry key. Once an embedder's crashpad client is connected to a crashpad handler (e.g. through SetIpcPipeName()) the embedder calls RegisterWerModule. Internally, this registration includes handles used to trigger the crashpad handler, an area reserved to hold an exception and context, and structures needed by the crashpad handler. Following a crash: WerFault.exe handles the crash then validates and loads the helper module. WER hands the helper module a handle to the crashing target process and copies of the exception and context for the faulting thread. The helper then copies out the client's registration data and duplicates handles to the crashpad handler, then fills back the various structures in the paused client that the crashpad handler will need. The helper then signals the crashpad handler, which collects a dump then notifies the helper that it is done. Support: WerRegisterExceptionHelperModule has been availble since at least Windows 7 but WerFault would not pass on the exceptions that crashpad could not already handle. This changed in Windows 10 20H1 (19041), which supports HKCU and HKLM registrations, and passes in more types of crashes. It is harmless to register the module for earlier versions of Windows as it simply won't be loaded by WerFault.exe. Tests: snapshot/win/end_to_end_test.py has been refactored slightly to group crash generation and output validation in main() by breaking up RunTests into smaller functions. As the module works by being loaded in WerFault.exe it is tested in end_to_end_test.py. Bug: crashpad:133, 866033, 865632 Change-Id: Id668bd15a510a24c79753e1bb03e9456f41a9780 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3677284 Reviewed-by: Joshua Peraza Commit-Queue: Alex Gough --- client/BUILD.gn | 5 +- client/crashpad_client.h | 15 ++ client/crashpad_client_win.cc | 74 +++++--- handler/BUILD.gn | 21 ++- handler/win/fastfail_test_program.cc | 146 +++++++++++++++ handler/win/wer/BUILD.gn | 47 +++++ handler/win/wer/crashpad_wer.cc | 177 ++++++++++++++++++ handler/win/wer/crashpad_wer.def | 20 ++ handler/win/wer/crashpad_wer.h | 45 +++++ handler/win/wer/crashpad_wer.ver | 2 + handler/win/wer/crashpad_wer_main.cc | 83 ++++++++ .../win/wer/crashpad_wer_module_unittest.cc | 86 +++++++++ snapshot/win/end_to_end_test.py | 121 +++++++++--- util/BUILD.gn | 13 ++ util/win/registration_protocol_win.h | 42 +++++ 15 files changed, 849 insertions(+), 48 deletions(-) create mode 100644 handler/win/fastfail_test_program.cc create mode 100644 handler/win/wer/BUILD.gn create mode 100644 handler/win/wer/crashpad_wer.cc create mode 100644 handler/win/wer/crashpad_wer.def create mode 100644 handler/win/wer/crashpad_wer.h create mode 100644 handler/win/wer/crashpad_wer.ver create mode 100644 handler/win/wer/crashpad_wer_main.cc create mode 100644 handler/win/wer/crashpad_wer_module_unittest.cc diff --git a/client/BUILD.gn b/client/BUILD.gn index 1a83efa2bb..359d57eda8 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -195,7 +195,10 @@ source_set("client_test") { } if (crashpad_is_win) { - data_deps += [ "../handler:crashpad_handler_console" ] + data_deps += [ + "../handler:crashpad_handler_console", + "../handler/win/wer:crashpad_wer_handler", + ] } } diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 1063dcf740..17103d263f 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -669,6 +669,21 @@ class CrashpadClient { //! error message will have been logged. bool WaitForHandlerStart(unsigned int timeout_ms); + //! \brief Register a DLL using WerRegisterExceptionModule(). + //! + //! This method should only be called after a successful call to + //! SetHandlerIPCPipe() or StartHandler(). The registration is valid for the + //! lifetime of this object. + //! + //! \param[in] full_path The full path to the DLL that will be registered. + //! The DLL path should also be set in an appropriate + //! `Windows Error Reporting` registry key. + //! + //! \return `true` if the DLL was registered. Note: Windows just stashes the + //! path somewhere so this returns `true` even if the DLL is not yet + //! set in an appropriate registry key, or does not exist. + bool RegisterWerModule(const std::wstring& full_path); + //! \brief Requests that the handler capture a dump even though there hasn't //! been a crash. //! diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 1275d7d75b..c443029dda 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -61,19 +63,25 @@ HANDLE g_signal_exception = INVALID_HANDLE_VALUE; // Where we store the exception information that the crash handler reads. ExceptionInformation g_crash_exception_information; -// These handles are never closed. g_signal_non_crash_dump is used to signal to -// the server to take a dump (not due to an exception), and the server will -// signal g_non_crash_dump_done when the dump is completed. -HANDLE g_signal_non_crash_dump = INVALID_HANDLE_VALUE; -HANDLE g_non_crash_dump_done = INVALID_HANDLE_VALUE; - -// Guards multiple simultaneous calls to DumpWithoutCrash(). This is leaked. +// Guards multiple simultaneous calls to DumpWithoutCrash() in the client. +// This is leaked. base::Lock* g_non_crash_dump_lock; // Where we store a pointer to the context information when taking a non-crash // dump. ExceptionInformation g_non_crash_exception_information; +// Context for the out-of-process exception handler module and holds non-crash +// dump handles. Handles are never closed once created. +WerRegistration g_wer_registration = {WerRegistration::kWerRegistrationVersion, + INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE, + false, + nullptr, + {0}, + {0}, + {0}}; + enum class StartupState : int { kNotReady = 0, // This must be value 0 because it is the initial value of a // global AtomicWord. @@ -402,8 +410,8 @@ bool StartHandlerProcess( InitialClientData initial_client_data( g_signal_exception, - g_signal_non_crash_dump, - g_non_crash_dump_done, + g_wer_registration.dump_without_crashing, + g_wer_registration.dump_completed, data->ipc_pipe_handle.get(), this_process.get(), FromPointerCast(&g_crash_exception_information), @@ -467,8 +475,8 @@ bool StartHandlerProcess( handle_list.reserve(8); handle_list.push_back(g_signal_exception); - handle_list.push_back(g_signal_non_crash_dump); - handle_list.push_back(g_non_crash_dump_done); + handle_list.push_back(g_wer_registration.dump_without_crashing); + handle_list.push_back(g_wer_registration.dump_completed); handle_list.push_back(data->ipc_pipe_handle.get()); handle_list.push_back(this_process.get()); AddHandleToListIfValidAndInheritable(&handle_list, @@ -625,9 +633,9 @@ bool CrashpadClient::StartHandler( g_signal_exception = CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); - g_signal_non_crash_dump = + g_wer_registration.dump_without_crashing = CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); - g_non_crash_dump_done = + g_wer_registration.dump_completed = CreateEvent(&security_attributes, false /* auto reset */, false, nullptr); CommonInProcessInitialization(); @@ -679,8 +687,8 @@ bool CrashpadClient::SetHandlerIPCPipe(const std::wstring& ipc_pipe) { DCHECK(!ipc_pipe_.empty()); DCHECK_EQ(g_signal_exception, INVALID_HANDLE_VALUE); - DCHECK_EQ(g_signal_non_crash_dump, INVALID_HANDLE_VALUE); - DCHECK_EQ(g_non_crash_dump_done, INVALID_HANDLE_VALUE); + DCHECK_EQ(g_wer_registration.dump_without_crashing, INVALID_HANDLE_VALUE); + DCHECK_EQ(g_wer_registration.dump_completed, INVALID_HANDLE_VALUE); DCHECK(!g_critical_section_with_debug_info.DebugInfo); DCHECK(!g_non_crash_dump_lock); @@ -712,9 +720,9 @@ bool CrashpadClient::SetHandlerIPCPipe(const std::wstring& ipc_pipe) { // The server returns these already duplicated to be valid in this process. g_signal_exception = IntToHandle(response.registration.request_crash_dump_event); - g_signal_non_crash_dump = + g_wer_registration.dump_without_crashing = IntToHandle(response.registration.request_non_crash_dump_event); - g_non_crash_dump_done = + g_wer_registration.dump_completed = IntToHandle(response.registration.non_crash_dump_completed_event); return true; @@ -749,10 +757,29 @@ bool CrashpadClient::WaitForHandlerStart(unsigned int timeout_ms) { return exit_code == 0; } +bool CrashpadClient::RegisterWerModule(const std::wstring& path) { + if (g_wer_registration.dump_completed == INVALID_HANDLE_VALUE || + g_wer_registration.dump_without_crashing == INVALID_HANDLE_VALUE) { + LOG(ERROR) << "not connected"; + return false; + } + // We cannot point (*context).exception_pointers to our pointers yet as it + // might get used for other non-crash dumps. + g_wer_registration.crashpad_exception_info = + &g_non_crash_exception_information; + // we can point these as we are the only users. + g_wer_registration.pointers.ExceptionRecord = &g_wer_registration.exception; + g_wer_registration.pointers.ContextRecord = &g_wer_registration.context; + + HRESULT res = + WerRegisterRuntimeExceptionModule(path.c_str(), &g_wer_registration); + return res == S_OK; +} + // static void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { - if (g_signal_non_crash_dump == INVALID_HANDLE_VALUE || - g_non_crash_dump_done == INVALID_HANDLE_VALUE) { + if (g_wer_registration.dump_without_crashing == INVALID_HANDLE_VALUE || + g_wer_registration.dump_completed == INVALID_HANDLE_VALUE) { LOG(ERROR) << "not connected"; return; } @@ -760,7 +787,7 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { if (BlockUntilHandlerStartedOrFailed() == StartupState::kFailed) { // If we know for certain that the handler has failed to start, then abort // here, as we would otherwise wait indefinitely for the - // g_non_crash_dump_done event that would never be signalled. + // g_wer_registration.dump_completed event that would never be signalled. LOG(ERROR) << "crash server failed to launch, no dump captured"; return; } @@ -798,11 +825,14 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { g_non_crash_exception_information.exception_pointers = FromPointerCast(&exception_pointers); - bool set_event_result = !!SetEvent(g_signal_non_crash_dump); + g_wer_registration.in_dump_without_crashing = true; + bool set_event_result = !!SetEvent(g_wer_registration.dump_without_crashing); PLOG_IF(ERROR, !set_event_result) << "SetEvent"; - DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); + DWORD wfso_result = + WaitForSingleObject(g_wer_registration.dump_completed, INFINITE); PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; + g_wer_registration.in_dump_without_crashing = false; } // static diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 0fe4760db7..e79f4719b3 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -145,7 +145,10 @@ source_set("handler_test") { ] if (crashpad_is_win) { - deps += [ "../minidump:test_support" ] + deps += [ + "../minidump:test_support", + "win/wer:crashpad_wer_test", + ] data_deps = [ ":crashpad_handler_test_extended_handler", @@ -353,4 +356,20 @@ if (crashpad_is_win) { ] } } + + config("enable_cfg") { + cflags = [ "/guard:cf" ] + ldflags = [ "/guard:cf" ] + } + crashpad_executable("fastfail_program") { + testonly = true + + sources = [ "win/fastfail_test_program.cc" ] + configs = [ ":enable_cfg" ] + + deps = [ + "../client", + "../third_party/mini_chromium:base", + ] + } } diff --git a/handler/win/fastfail_test_program.cc b/handler/win/fastfail_test_program.cc new file mode 100644 index 0000000000..1c33a6a06f --- /dev/null +++ b/handler/win/fastfail_test_program.cc @@ -0,0 +1,146 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "base/files/file_path.h" +#include "base/logging.h" +#include "client/crashpad_client.h" +#include "util/misc/paths.h" + +#include + +// We set up a program that crashes with a CFG exception so must be built and +// linked with /guard:cf. We register the crashpad runtime exception helper +// module to intercept and trigger the crashpad handler. Note that Windows only +// loads the module in WerFault after the crash for Windows 10 >= 20h1 (19041). +namespace crashpad { +namespace { + +// This function should not be on our stack as CFG prevents the modified +// icall from happening. +int CallRffeManyTimes() { + RaiseFailFastException(nullptr, nullptr, 0); + RaiseFailFastException(nullptr, nullptr, 0); + RaiseFailFastException(nullptr, nullptr, 0); + RaiseFailFastException(nullptr, nullptr, 0); + return 1; +} + +using FuncType = decltype(&CallRffeManyTimes); +void IndirectCall(FuncType* func) { + // This code always generates CFG guards. + (*func)(); +} + +void CfgCrash() { + // Call into the middle of the Crashy function. + FuncType func = reinterpret_cast( + (reinterpret_cast(CallRffeManyTimes)) + 16); + __try { + // Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers. + IndirectCall(&func); + } __except (EXCEPTION_EXECUTE_HANDLER) { + // CFG fast fail should never be caught. + CHECK(false); + } + // Should only reach here if CFG is disabled. + abort(); +} + +void FastFailCrash() { + __fastfail(77); +} + +int CrashyMain(int argc, wchar_t* argv[]) { + static CrashpadClient* client = new crashpad::CrashpadClient(); + + std::wstring type; + if (argc == 3) { + type = argv[2]; + // We call this from end_to_end_test.py. + if (!client->SetHandlerIPCPipe(argv[1])) { + LOG(ERROR) << "SetHandler"; + return EXIT_FAILURE; + } + } else if (argc == 4) { + type = argv[3]; + // This is helpful for debugging. + if (!client->StartHandler(base::FilePath(argv[1]), + base::FilePath(argv[2]), + base::FilePath(), + std::string(), + std::map(), + std::vector(), + false, + true)) { + LOG(ERROR) << "StartHandler"; + return EXIT_FAILURE; + } + // Got to have a handler & registration. + if (!client->WaitForHandlerStart(10000)) { + LOG(ERROR) << "Handler failed to start"; + return EXIT_FAILURE; + } + } else { + fprintf(stderr, "Usage: %ls [cf|ff]\n", argv[0]); + fprintf( + stderr, " %ls [cf|ff]\n", argv[0]); + return EXIT_FAILURE; + } + + base::FilePath exe_path; + if (!Paths::Executable(&exe_path)) { + LOG(ERROR) << "Failed getting path"; + return EXIT_FAILURE; + } + + // Find the module. + auto mod_path = exe_path.DirName().Append(L"crashpad_wer.dll"); + + // Make sure it is registered in the registry. + DWORD dwOne = 1; + LSTATUS reg_res = + RegSetKeyValueW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\Windows Error Reporting\\" + L"RuntimeExceptionHelperModules", + mod_path.value().c_str(), + REG_DWORD, + &dwOne, + sizeof(DWORD)); + if (reg_res != ERROR_SUCCESS) { + LOG(ERROR) << "RegSetKeyValueW"; + return EXIT_FAILURE; + } + + if (!client->RegisterWerModule(mod_path.value())) { + LOG(ERROR) << "WerRegisterRuntimeExceptionModule"; + return EXIT_FAILURE; + } + + if (type == L"cf") + CfgCrash(); + if (type == L"ff") + FastFailCrash(); + + LOG(ERROR) << "Invalid type or exception failed."; + return EXIT_FAILURE; +} + +} // namespace +} // namespace crashpad + +int wmain(int argc, wchar_t* argv[]) { + return crashpad::CrashyMain(argc, argv); +} diff --git a/handler/win/wer/BUILD.gn b/handler/win/wer/BUILD.gn new file mode 100644 index 0000000000..5fc38efdd9 --- /dev/null +++ b/handler/win/wer/BUILD.gn @@ -0,0 +1,47 @@ +# Copyright 2022 The Crashpad Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../../../build/crashpad_buildconfig.gni") + +assert(crashpad_is_win) + +# Allows other projects (e.g. Chrome) to wrap this as a dll. +source_set("crashpad_wer_handler") { + sources = [ + "crashpad_wer.cc", + "crashpad_wer.h", + ] + deps = [ "../../../util:util_registration_protocol" ] +} + +crashpad_loadable_module("crashpad_wer") { + sources = [ + "crashpad_wer.def", + "crashpad_wer_main.cc", + ] + deps = [ ":crashpad_wer_handler" ] + configs = [ "../../../:crashpad_config" ] +} + +source_set("crashpad_wer_test") { + testonly = true + sources = [ "crashpad_wer_module_unittest.cc" ] + deps = [ + ":crashpad_wer", + ":crashpad_wer_handler", + "../../../client:client", + "../../../test:test", + "../../../third_party/googletest:googletest", + ] +} diff --git a/handler/win/wer/crashpad_wer.cc b/handler/win/wer/crashpad_wer.cc new file mode 100644 index 0000000000..f3de028e0e --- /dev/null +++ b/handler/win/wer/crashpad_wer.cc @@ -0,0 +1,177 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// See: +// https://docs.microsoft.com/en-us/windows/win32/api/werapi/nf-werapi-werregisterruntimeexceptionmodule + +#include "handler/win/wer/crashpad_wer.h" + +#include "util/misc/address_types.h" +#include "util/win/registration_protocol_win.h" + +#include +#include + +namespace crashpad::wer { +namespace { +using crashpad::WerRegistration; + +// We have our own version of this to avoid pulling in //base. +class ScopedHandle { + public: + ScopedHandle() : handle_(INVALID_HANDLE_VALUE) {} + ScopedHandle(HANDLE from) : handle_(from) {} + ~ScopedHandle() { + if (IsValid()) + CloseHandle(handle_); + } + bool IsValid() { + if (handle_ == INVALID_HANDLE_VALUE || handle_ == 0) + return false; + return true; + } + HANDLE Get() { return handle_; } + + private: + HANDLE handle_; +}; + +ScopedHandle DuplicateFromTarget(HANDLE target_process, HANDLE target_handle) { + HANDLE hTmp; + if (!DuplicateHandle(target_process, + target_handle, + GetCurrentProcess(), + &hTmp, + SYNCHRONIZE | EVENT_MODIFY_STATE, + false, + 0)) { + return ScopedHandle(); + } + return ScopedHandle(hTmp); +} + +bool ProcessException(std::vector& handled_exceptions, + const PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION e_info) { + // Need to have been given a context. + if (!pContext) + return false; + + if (!e_info->bIsFatal) + return false; + + // Only deal with exceptions that crashpad would not have handled. + if (handled_exceptions.size() && + std::find(handled_exceptions.begin(), + handled_exceptions.end(), + e_info->exceptionRecord.ExceptionCode) == + handled_exceptions.end()) { + return false; + } + + // Grab out the handles to the crashpad server. + WerRegistration target_registration = {}; + if (!ReadProcessMemory(e_info->hProcess, + pContext, + &target_registration, + sizeof(target_registration), + nullptr)) { + return false; + } + + // Validate version of registration struct. + if (target_registration.version != WerRegistration::kWerRegistrationVersion) + return false; + + // Dupe handles for triggering the dump. + auto dump_start = DuplicateFromTarget( + e_info->hProcess, target_registration.dump_without_crashing); + auto dump_done = + DuplicateFromTarget(e_info->hProcess, target_registration.dump_completed); + + if (!dump_start.IsValid() || !dump_done.IsValid()) + return false; + + // It's possible that the target crashed while inside a DumpWithoutCrashing + // call - either in the DumpWithoutCrashing call or in another thread - if so + // we cannot trigger the dump until the first call's crash is dealth with as + // the crashpad handler might be reading from structures we will write to. We + // give the event a short while to be triggered and give up if it is not + // signalled. + if (target_registration.in_dump_without_crashing) { + constexpr DWORD kOneSecondInMs = 1000; + DWORD wait_result = WaitForSingleObject(dump_done.Get(), kOneSecondInMs); + if (wait_result != WAIT_OBJECT_0) + return false; + } + + // Set up the crashpad handler's info structure. + crashpad::ExceptionInformation target_non_crash_exception_info{}; + target_non_crash_exception_info.thread_id = GetThreadId(e_info->hThread); + target_non_crash_exception_info.exception_pointers = + static_cast(reinterpret_cast(pContext)) + + offsetof(WerRegistration, pointers); + + if (!WriteProcessMemory(e_info->hProcess, + target_registration.crashpad_exception_info, + &target_non_crash_exception_info, + sizeof(target_non_crash_exception_info), + nullptr)) { + return false; + } + + // Write Exception & Context to the areas reserved by the client. + if (!WriteProcessMemory( + e_info->hProcess, + reinterpret_cast(target_registration.pointers.ExceptionRecord), + &e_info->exceptionRecord, + sizeof(e_info->exceptionRecord), + nullptr)) { + return false; + } + if (!WriteProcessMemory( + e_info->hProcess, + reinterpret_cast(target_registration.pointers.ContextRecord), + &e_info->context, + sizeof(e_info->context), + nullptr)) { + return false; + } + + // Request dump. + if (!SetEvent(dump_start.Get())) + return false; + + constexpr DWORD kTenSecondsInMs = 10 * 1000; + DWORD result = WaitForSingleObject(dump_done.Get(), kTenSecondsInMs); + + if (result == WAIT_OBJECT_0) { + // The handler signalled that it has written a dump, so we can terminate the + // target - this takes over from WER, sorry WER. + TerminateProcess(e_info->hProcess, e_info->exceptionRecord.ExceptionCode); + return true; + } + // Maybe some other handler can have a go. + return false; +} +} // namespace + +bool ExceptionEvent( + std::vector& handled_exceptions, + const PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation) { + return ProcessException(handled_exceptions, pContext, pExceptionInformation); +} + +} // namespace crashpad::wer diff --git a/handler/win/wer/crashpad_wer.def b/handler/win/wer/crashpad_wer.def new file mode 100644 index 0000000000..57ec676fe8 --- /dev/null +++ b/handler/win/wer/crashpad_wer.def @@ -0,0 +1,20 @@ +; Copyright 2022 The Crashpad Authors. All rights reserved. +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. +LIBRARY "crashpad_wer.dll" + +EXPORTS + ; These are required for the WER api. + OutOfProcessExceptionEventCallback + OutOfProcessExceptionEventSignatureCallback + OutOfProcessExceptionEventDebuggerLaunchCallback diff --git a/handler/win/wer/crashpad_wer.h b/handler/win/wer/crashpad_wer.h new file mode 100644 index 0000000000..5a3a52f901 --- /dev/null +++ b/handler/win/wer/crashpad_wer.h @@ -0,0 +1,45 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_HANDLER_WIN_WER_CRASHPAD_WER_H_ +#define CRASHPAD_HANDLER_WIN_WER_CRASHPAD_WER_H_ + +#include + +#include +#include + +namespace crashpad::wer { +//! \brief Embedder calls this from OutOfProcessExceptionEventCallback(). +//! +//! In the embedder's WER runtime exception helper, call this during +//! OutOfProcessExceptionEventCallback(). +//! +//! \param[in] handled_exceptions is a list of exception codes that the helper +//! should pass on to crashpad handler (if possible). Provide an empty list +//! to pass every exception on to the crashpad handler. +//! \param[in] pContext is the context provided by WerFault to the helper. +//! \param[in] pExceptionInformation is the exception information provided by +//! WerFault to the helper DLL. +//! +//! \return `true` if the target process was dumped by the crashpad handler then +//! terminated, or `false` otherwise. +bool ExceptionEvent( + std::vector& handled_exceptions, + const PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation); + +} // namespace crashpad::wer + +#endif // CRASHPAD_HANDLER_WIN_WER_CRASHPAD_WER_H_ diff --git a/handler/win/wer/crashpad_wer.ver b/handler/win/wer/crashpad_wer.ver new file mode 100644 index 0000000000..0fee2e9f91 --- /dev/null +++ b/handler/win/wer/crashpad_wer.ver @@ -0,0 +1,2 @@ +INTERNAL_NAME=crashpad_wer +ORIGINAL_FILENAME=crashpad_wer.dll diff --git a/handler/win/wer/crashpad_wer_main.cc b/handler/win/wer/crashpad_wer_main.cc new file mode 100644 index 0000000000..4613b35353 --- /dev/null +++ b/handler/win/wer/crashpad_wer_main.cc @@ -0,0 +1,83 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// See: +// https://docs.microsoft.com/en-us/windows/win32/api/werapi/nf-werapi-werregisterruntimeexceptionmodule + +#include "handler/win/wer/crashpad_wer.h" + +#include +#include + +// Functions that will be exported from the DLL. +extern "C" { +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { + return true; +} + +// PFN_WER_RUNTIME_EXCEPTION_EVENT +// pContext is the address of a crashpad::internal::WerRegistration in the +// target process. +HRESULT OutOfProcessExceptionEventCallback( + PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation, + BOOL* pbOwnershipClaimed, + PWSTR pwszEventName, + PDWORD pchSize, + PDWORD pdwSignatureCount) { + std::vector wanted_exceptions = { + 0xC0000602, // STATUS_FAIL_FAST_EXCEPTION + 0xC0000409, // STATUS_STACK_BUFFER_OVERRUN + }; + // Default to not-claiming as bailing out is easier. + *pbOwnershipClaimed = FALSE; + bool result = crashpad::wer::ExceptionEvent( + wanted_exceptions, pContext, pExceptionInformation); + + if (result) { + *pbOwnershipClaimed = TRUE; + // Technically we failed as we terminated the process. + return E_FAIL; + } + // Pass. + return S_OK; +} + +// PFN_WER_RUNTIME_EXCEPTION_EVENT_SIGNATURE +HRESULT OutOfProcessExceptionEventSignatureCallback( + PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation, + DWORD dwIndex, + PWSTR pwszName, + PDWORD pchName, + PWSTR pwszValue, + PDWORD pchValue) { + // We handle everything in the call to OutOfProcessExceptionEventCallback. + // This function should never be called. + return E_FAIL; +} + +// PFN_WER_RUNTIME_EXCEPTION_DEBUGGER_LAUNCH +HRESULT OutOfProcessExceptionEventDebuggerLaunchCallback( + PVOID pContext, + const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation, + PBOOL pbIsCustomDebugger, + PWSTR pwszDebuggerLaunch, + PDWORD pchDebuggerLaunch, + PBOOL pbIsDebuggerAutolaunch) { + // We handle everything in the call to OutOfProcessExceptionEventCallback. + // This function should never be called. + return E_FAIL; +} +} // extern "C" diff --git a/handler/win/wer/crashpad_wer_module_unittest.cc b/handler/win/wer/crashpad_wer_module_unittest.cc new file mode 100644 index 0000000000..efd8392ca2 --- /dev/null +++ b/handler/win/wer/crashpad_wer_module_unittest.cc @@ -0,0 +1,86 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "client/crashpad_client.h" + +#include "base/files/file_path.h" +#include "gtest/gtest.h" +#include "test/test_paths.h" +#include "util/win/registration_protocol_win.h" + +#include +#include + +namespace crashpad { +namespace test { +namespace { +base::FilePath ModulePath() { + auto dir = TestPaths::Executable().DirName(); + return dir.Append(FILE_PATH_LITERAL("crashpad_wer.dll")); +} + +// Quick sanity check of the module, can't really test dumping etc. outside of +// WerFault.exe loading it. +TEST(CrashpadWerModule, Basic) { + HRESULT res = 0; + // Module loads. + HMODULE hMod = LoadLibraryW(ModulePath().value().c_str()); + ASSERT_TRUE(hMod); + + // Required functions exist. + auto wref = reinterpret_cast( + GetProcAddress(hMod, WER_RUNTIME_EXCEPTION_EVENT_FUNCTION)); + ASSERT_TRUE(wref); + auto wrees = reinterpret_cast( + GetProcAddress(hMod, WER_RUNTIME_EXCEPTION_EVENT_SIGNATURE_FUNCTION)); + ASSERT_TRUE(wrees); + auto wredl = reinterpret_cast( + GetProcAddress(hMod, WER_RUNTIME_EXCEPTION_DEBUGGER_LAUNCH)); + ASSERT_TRUE(wredl); + + // Not-implemented functions return E_FAIL as expected. + res = wrees(nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr); + ASSERT_EQ(res, E_FAIL); + res = wredl(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + ASSERT_EQ(res, E_FAIL); + + // Dummy args for OutOfProcessExceptionEventCallback. + crashpad::WerRegistration registration; + WER_RUNTIME_EXCEPTION_INFORMATION wer_ex; + BOOL bClaimed = FALSE; + + // No context => skip. + res = wref(nullptr, &wer_ex, &bClaimed, nullptr, nullptr, nullptr); + ASSERT_EQ(res, S_OK); + ASSERT_EQ(bClaimed, FALSE); + + // Non-fatal exceptions are skipped. + wer_ex.bIsFatal = FALSE; + res = wref(®istration, &wer_ex, &bClaimed, nullptr, nullptr, nullptr); + ASSERT_EQ(res, S_OK); + ASSERT_EQ(bClaimed, FALSE); + + // Fatal exception with unhandled code is skipped. + wer_ex.bIsFatal = TRUE; + wer_ex.exceptionRecord.ExceptionCode = 0xc0000005; + res = wref(®istration, &wer_ex, &bClaimed, nullptr, nullptr, nullptr); + ASSERT_EQ(res, S_OK); + ASSERT_EQ(bClaimed, FALSE); + + FreeLibrary(hMod); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py index 9d319078d8..ff307e123c 100755 --- a/snapshot/win/end_to_end_test.py +++ b/snapshot/win/end_to_end_test.py @@ -87,6 +87,15 @@ def GetCdbPath(): return None +def Win32_20H1(): + (major, _, build) = platform.win32_ver()[1].split('.') + if int(major) < 10: + return False + if int(build) >= 19041: + return True + return False + + def NamedPipeExistsAndReady(pipe_name): """Returns False if pipe_name does not exist. If pipe_name does exist, blocks until the pipe is ready to service clients, and then returns True. @@ -203,6 +212,12 @@ def GetDumpFromZ7Program(out_dir, pipe_name): win32con.EXCEPTION_ACCESS_VIOLATION) +def GetDumpFromFastFailProgram(out_dir, pipe_name, *args): + STATUS_STACK_BUFFER_OVERRUN = 0xc0000409 + return GetDumpFromProgram(out_dir, pipe_name, 'fastfail_program.exe', + STATUS_STACK_BUFFER_OVERRUN, *args) + + class CdbRun(object): """Run cdb.exe passing it a cdb command and capturing the output. `Check()` searches for regex patterns in sequence allowing verification of @@ -215,18 +230,25 @@ def __init__(self, cdb_path, dump_path, command): self.out = subprocess.check_output( [cdb_path, '-z', dump_path, '-c', command + ';q'], text=True) - def Check(self, pattern, message, re_flags=0): + def Check(self, pattern, message, re_flags=0, must_not_match=False): match_obj = re.search(pattern, self.out, re_flags) - if match_obj: + if match_obj and not must_not_match: # Matched. Consume up to end of match. self.out = self.out[match_obj.end(0):] print('ok - %s' % message) sys.stdout.flush() + elif must_not_match and not match_obj: + # Did not match and did not want to match. + print('ok - %s' % message) + sys.stdout.flush() else: print('-' * 80, file=sys.stderr) print('FAILED - %s' % message, file=sys.stderr) print('-' * 80, file=sys.stderr) - print('did not match:\n %s' % pattern, file=sys.stderr) + if must_not_match: + print('unexpected match:\n %s' % pattern, file=sys.stderr) + else: + print('did not match:\n %s' % pattern, file=sys.stderr) print('-' * 80, file=sys.stderr) print('remaining output was:\n %s' % self.out, file=sys.stderr) print('-' * 80, file=sys.stderr) @@ -244,8 +266,7 @@ def Find(self, pattern, re_flags=0): def RunTests(cdb_path, dump_path, start_handler_dump_path, destroyed_dump_path, - z7_dump_path, other_program_path, other_program_no_exception_path, - sigabrt_main_path, sigabrt_background_path, pipe_name): + pipe_name): """Runs various tests in sequence. Runs a new cdb instance on the dump for each block of tests to reduce the chances that output from one command is confused for output from another. @@ -373,17 +394,22 @@ def RunTests(cdb_path, dump_path, start_handler_dump_path, destroyed_dump_path, out.Check(r'type \?\?\? \(333333\), size 00001000', 'first user stream') out.Check(r'type \?\?\? \(222222\), size 00000080', 'second user stream') - if z7_dump_path: - out = CdbRun(cdb_path, z7_dump_path, '.ecxr;lm') - out.Check('This dump file has an exception of interest stored in it', - 'captured exception in z7 module') - # Older versions of cdb display relative to exports for /Z7 modules, - # newer ones just display the offset. - out.Check(r'z7_test(!CrashMe\+0xe|\+0x100e):', - 'exception in z7 at correct location') - out.Check(r'z7_test C \(codeview symbols\) z7_test\.dll', - 'expected non-pdb symbol format') +def Run7zDumpTest(cdb_path, z7_dump_path): + """Validate output when non-pdb symbols are in a module.""" + out = CdbRun(cdb_path, z7_dump_path, '.ecxr;lm') + out.Check('This dump file has an exception of interest stored in it', + 'captured exception in z7 module') + # Older versions of cdb display relative to exports for /Z7 modules, + # newer ones just display the offset. + out.Check(r'z7_test(!CrashMe\+0xe|\+0x100e):', + 'exception in z7 at correct location') + out.Check(r'z7_test C \(codeview symbols\) z7_test\.dll', + 'expected non-pdb symbol format') + + +def RunOtherProgramTests(cdb_path, other_program_path, + other_program_no_exception_path): out = CdbRun(cdb_path, other_program_path, '.ecxr;k;~') out.Check('Unknown exception - code deadbea7', 'other program dump exception code') @@ -407,6 +433,9 @@ def RunTests(cdb_path, dump_path, start_handler_dump_path, destroyed_dump_path, 'other program with no exception given') out.Check('!RaiseException', 'other program in RaiseException()') + +def RunSigAbrtTest(cdb_path, sigabrt_main_path, sigabrt_background_path): + """Validate that abort signals are collected.""" out = CdbRun(cdb_path, sigabrt_main_path, '.ecxr') out.Check('code 40000015', 'got sigabrt signal') out.Check('::HandleAbortSignal', ' stack in expected location') @@ -415,6 +444,32 @@ def RunTests(cdb_path, dump_path, start_handler_dump_path, destroyed_dump_path, out.Check('code 40000015', 'got sigabrt signal from background thread') +def RunFastFailDumpTest(cdb_path, fastfail_path): + """Runs tests on __fastfail() caught using the runtime exception helper.""" + out = CdbRun(cdb_path, fastfail_path, '.ecxr;k') + out.Check('This dump file has an exception of interest stored in it', + 'captured exception from __fastfail() crash()') + out.Check(r'Subcode: 0x4d \(unknown subcode\)', 'See expected subcode.') + out.Check('FastFailCrash', 'See expected throwing function.') + out = CdbRun(cdb_path, fastfail_path, '.ecxr;k') + + +def RunCfgDumpTest(cdb_path, cfg_path): + """Runs tests on a cfg crash caught using the runtime exception helper.""" + out = CdbRun(cdb_path, cfg_path, '.ecxr;k') + out.Check('This dump file has an exception of interest stored in it', + 'captured exception from cfg crash()') + out.Check('Subcode: 0xa FAST_FAIL_GUARD_ICALL_CHECK_FAILURE', + 'See expected cfg error code.') + out.Check('RtlFailFast', + 'See expected Windows exception throwing function.') + out.Check('::CfgCrash', 'expected crashy function is on the stack.') + out = CdbRun(cdb_path, cfg_path, '.ecxr;k') + out.Check(r'CallRffeManyTimes', + 'Do not see the function we fiddled the pointer for.', + must_not_match=True) + + def main(args): try: if len(args) != 1: @@ -437,6 +492,7 @@ def main(args): pipe_name = r'\\.\pipe\end-to-end_%s_%s' % (os.getpid(), str(random.getrandbits(64))) + # Basic tests. crashy_dump_path = GetDumpFromCrashyProgram(args[0], pipe_name) if not crashy_dump_path: return 1 @@ -450,12 +506,10 @@ def main(args): if not destroyed_dump_path: return 1 - z7_dump_path = None - if not args[0].endswith('_x64'): - z7_dump_path = GetDumpFromZ7Program(args[0], pipe_name) - if not z7_dump_path: - return 1 + RunTests(cdb_path, crashy_dump_path, start_handler_dump_path, + destroyed_dump_path, pipe_name) + # Other program dumps. other_program_path = GetDumpFromOtherProgram(args[0], pipe_name) if not other_program_path: return 1 @@ -465,6 +519,10 @@ def main(args): if not other_program_no_exception_path: return 1 + RunOtherProgramTests(cdb_path, other_program_path, + other_program_no_exception_path) + + # SIGABRT. sigabrt_main_path = GetDumpFromSignal(args[0], pipe_name, 'main') if not sigabrt_main_path: return 1 @@ -474,10 +532,25 @@ def main(args): if not sigabrt_background_path: return 1 - RunTests(cdb_path, crashy_dump_path, start_handler_dump_path, - destroyed_dump_path, z7_dump_path, other_program_path, - other_program_no_exception_path, sigabrt_main_path, - sigabrt_background_path, pipe_name) + RunSigAbrtTest(cdb_path, sigabrt_main_path, sigabrt_background_path) + + # Can only build the z7 program on x86. + if not args[0].endswith('_x64'): + z7_dump_path = GetDumpFromZ7Program(args[0], pipe_name) + if not z7_dump_path: + return 1 + Run7zDumpTest(cdb_path, z7_dump_path) + + # __fastfail() & CFG crash caught by WerRuntimeExceptionHelperModule. + if (Win32_20H1()): + cfg_path = GetDumpFromFastFailProgram(args[0], pipe_name, "cf") + if not cfg_path: + return 1 + RunCfgDumpTest(cdb_path, cfg_path) + fastfail_path = GetDumpFromFastFailProgram(args[0], pipe_name, "ff") + if not fastfail_path: + return 1 + RunFastFailDumpTest(cdb_path, fastfail_path) return 1 if g_had_failures else 0 finally: diff --git a/util/BUILD.gn b/util/BUILD.gn index 6e6a8eec00..8a0a89062a 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -159,6 +159,19 @@ if (crashpad_is_mac || crashpad_is_ios) { } } +# Used by crashpad_wer_handler to avoid linking all of :util. +if (crashpad_is_win) { + source_set("util_registration_protocol") { + sources = [ + "misc/address_types.h", + "win/address_types.h", + "win/registration_protocol_win.h", + ] + public_deps = [ "../third_party/mini_chromium:build" ] + public_configs = [ "..:crashpad_config" ] + } +} + crashpad_static_library("util") { sources = [ "file/delimited_file_reader.cc", diff --git a/util/win/registration_protocol_win.h b/util/win/registration_protocol_win.h index 690d61242e..e467fd84a2 100644 --- a/util/win/registration_protocol_win.h +++ b/util/win/registration_protocol_win.h @@ -37,6 +37,48 @@ struct ExceptionInformation { DWORD thread_id; }; +//! \brief Context to be passed to WerRegisterRuntimeExceptionModule(). +//! +//! Used by the crashpad client, and the WER exception DLL. +struct WerRegistration { + //! \brief The expected value of `version`. This should be changed whenever + //! this struct is modified incompatibly. + enum { kWerRegistrationVersion = 1 }; + //! \brief Version field to detect skew between target process and helper. + //! Should be set to kWerRegistrationVersion. + int version; + //! \brief Used by DumpWithoutCrashing and the WER module to initiate a dump. + //! These handles are leaked in the client process. + HANDLE dump_without_crashing; + //! \brief Used by DumpWithoutCrashing to signal that a dump has been taken. + //! These handles are leaked in the client process. + HANDLE dump_completed; + //! \brief Set just before and cleared just after the events above are + //! triggered or signalled in a normal DumpWithoutCrashing call. + //! When `true` the WER handler should not set the exception structures until + //! after dump_completed has been signalled. + bool in_dump_without_crashing; + //! \brief Address of g_non_crash_exception_information. + //! + //! Provided by the target process. Just before dumping we will point + //! (*crashpad_exception_info).exception_pointers at `pointers`. As WerFault + //! loads the helper with the same bitness as the client this can be void*. + void* crashpad_exception_info; + //! \brief These will point into the `exception` and `context` members in this + //! structure. + //! + //! Filled in by the helper DLL. + EXCEPTION_POINTERS pointers; + //! \brief The exception provided by WerFault. + //! + //! Filled in by the helper DLL. + EXCEPTION_RECORD exception; + //! \brief The context provided by WerFault. + //! + //! Filled in by the helper DLL. + CONTEXT context; +}; + //! \brief A client registration request. struct RegistrationRequest { //! \brief The expected value of `version`. This should be changed whenever From 7a622b2f6baaacdff5c8f3acf7efe32b378b4ee7 Mon Sep 17 00:00:00 2001 From: Stephan Hartmann Date: Fri, 8 Jul 2022 19:24:46 +0200 Subject: [PATCH 201/478] GCC: fix invalid bind of packed field to uint32_t& GCC does not allow binding a packed field to an address. Assign to a intermediate variable instead before pushing to map. Bug: chromium:819294 Change-Id: I806e5f99c2b19e656b91a60f72172b59c961ba5f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3751392 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- snapshot/minidump/process_snapshot_minidump.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 28942447dc..b9e7ea294c 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -643,7 +643,9 @@ bool ProcessSnapshotMinidump::InitializeThreadNames() { return false; } - thread_names_.emplace(minidump_thread_name.ThreadId, std::move(name)); + // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566 + const uint32_t thread_id = minidump_thread_name.ThreadId; + thread_names_.emplace(thread_id, std::move(name)); } return true; From 14246325920a4dc4c5d2862a93721cc8a9590044 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 13 Jul 2022 13:15:36 -0400 Subject: [PATCH 202/478] ios: Fix testCrashWithDyldErrorString on arm64. Fixed when running a simulator on arm64 Apple Silicon. Change-Id: I6a6e917b4d5ff009683214794fe6a6af833be3c0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3758362 Reviewed-by: Rohit Rao Commit-Queue: Justin Cohen --- test/ios/crash_type_xctest.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 27b4e1f7fe..0bf0980e5e 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -286,7 +286,13 @@ - (void)testCrashWithDyldErrorString { return; } [rootObject_ crashWithDyldErrorString]; +#if defined(ARCH_CPU_X86_64) [self verifyCrashReportException:EXC_BAD_INSTRUCTION]; +#elif defined(ARCH_CPU_ARM64) + [self verifyCrashReportException:EXC_BREAKPOINT]; +#else +#error Port to your CPU architecture +#endif NSArray* vector = [rootObject_ getAnnotations][@"vector"]; // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp // ImageLoaderMachO::doInitialization(). From b7db85b62d791fbb006fd87acb81b07eba71efa0 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 14 Jul 2022 13:41:55 -0400 Subject: [PATCH 203/478] ios: vm_read module file path before calling strlen. Adds a new IOSIntermediateDumpWriter::AddPropertyCString method which takes an address to a cstring of unknown length and page-by-page searches for a NUL-byte terminator. This is necessary because currently WriteModuleInfo calls strlen directly on the dyld and module filePath without first using vm_read. On iOS14 this occasionally crashes, and is generally unwise. Instead, use AddPropertyCString. This patch also removes WriteDyldErrorStringAnnotation, as it's no longer used going forward with iOS 15. Bug: 1332862 Change-Id: I3801693bc39259a0127e5175dccf286a1cd97ba7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3689516 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- .../in_process_intermediate_dump_handler.cc | 135 +++--------------- util/ios/ios_intermediate_dump_writer.cc | 80 ++++++++++- util/ios/ios_intermediate_dump_writer.h | 28 +++- util/ios/ios_intermediate_dump_writer_test.cc | 74 ++++++++++ 4 files changed, 196 insertions(+), 121 deletions(-) diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index e7e9003e3b..6b431581d2 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -118,7 +118,7 @@ void WriteProperty(IOSIntermediateDumpWriter* writer, //! \param[in] writer The dump writer //! \param[in] key The key to write. //! \param[in] value Memory to be written. -//! \param[in] count Length of \a data. +//! \param[in] value_length Length of \a data. void WritePropertyBytes(IOSIntermediateDumpWriter* writer, IntermediateDumpKey key, const void* value, @@ -127,6 +127,20 @@ void WritePropertyBytes(IOSIntermediateDumpWriter* writer, WriteError(key); } +//! \brief Call AddPropertyCString with raw error log. +//! +//! \param[in] writer The dump writer +//! \param[in] key The key to write. +//! \param[in] max_length The maximum string length. +//! \param[in] value Memory to be written. +void WritePropertyCString(IOSIntermediateDumpWriter* writer, + IntermediateDumpKey key, + size_t max_length, + const char* value) { + if (!writer->AddPropertyCString(key, max_length, value)) + WriteError(key); +} + kern_return_t MachVMRegionRecurseDeepest(task_t task, vm_address_t* address, vm_size_t* size, @@ -498,80 +512,6 @@ void WriteAppleCrashReporterAnnotations( } } -void WriteDyldErrorStringAnnotation( - IOSIntermediateDumpWriter* writer, - const uint64_t address, - const symtab_command* symtab_command_ptr, - const dysymtab_command* dysymtab_command_ptr, - const segment_command_64* text_seg_ptr, - const segment_command_64* linkedit_seg_ptr, - vm_size_t slide) { - if (text_seg_ptr == nullptr || linkedit_seg_ptr == nullptr || - symtab_command_ptr == nullptr) { - return; - } - - ScopedVMRead symtab_command; - ScopedVMRead dysymtab_command; - ScopedVMRead text_seg; - ScopedVMRead linkedit_seg; - if (!symtab_command.Read(symtab_command_ptr) || - !text_seg.Read(text_seg_ptr) || !linkedit_seg.Read(linkedit_seg_ptr) || - (dysymtab_command_ptr && !dysymtab_command.Read(dysymtab_command_ptr))) { - CRASHPAD_RAW_LOG("Unable to load dyld symbol table."); - } - - uint64_t file_slide = - (linkedit_seg->vmaddr - text_seg->vmaddr) - linkedit_seg->fileoff; - uint64_t strings = address + (symtab_command->stroff + file_slide); - nlist_64* symbol_ptr = reinterpret_cast( - address + (symtab_command->symoff + file_slide)); - - // If a dysymtab is present, use it to filter the symtab for just the - // portion used for extdefsym. If no dysymtab is present, the entire symtab - // will need to be consulted. - uint32_t symbol_count = symtab_command->nsyms; - if (dysymtab_command_ptr) { - symbol_ptr += dysymtab_command->iextdefsym; - symbol_count = dysymtab_command->nextdefsym; - } - - for (uint32_t i = 0; i < symbol_count; i++, symbol_ptr++) { - ScopedVMRead symbol; - if (!symbol.Read(symbol_ptr)) { - CRASHPAD_RAW_LOG("Unable to load dyld symbol table symbol."); - return; - } - - if (!symbol->n_value) - continue; - - ScopedVMRead symbol_name; - if (!symbol_name.Read(strings + symbol->n_un.n_strx)) { - CRASHPAD_RAW_LOG("Unable to load dyld symbol name."); - } - - if (strcmp(symbol_name.get(), "_error_string") == 0) { - ScopedVMRead symbol_value; - if (!symbol_value.Read(symbol->n_value + slide)) { - CRASHPAD_RAW_LOG("Unable to load dyld symbol value."); - } - // 1024 here is distinct from kMaxMessageSize above, because it refers to - // a precisely-sized buffer inside dyld. - const size_t value_len = strnlen(symbol_value.get(), 1024); - if (value_len) { - WriteProperty(writer, - IntermediateDumpKey::kAnnotationsDyldErrorString, - symbol_value.get(), - value_len); - } - return; - } - - continue; - } -} - } // namespace // static @@ -980,10 +920,8 @@ void InProcessIntermediateDumpHandler::WriteModuleInfo( } if (image->imageFilePath) { - WriteProperty(writer, - IntermediateDumpKey::kName, - image->imageFilePath, - strlen(image->imageFilePath)); + WritePropertyCString( + writer, IntermediateDumpKey::kName, PATH_MAX, image->imageFilePath); } uint64_t address = FromPointerCast(image->imageLoadAddress); WriteProperty(writer, IntermediateDumpKey::kAddress, &address); @@ -995,10 +933,8 @@ void InProcessIntermediateDumpHandler::WriteModuleInfo( { IOSIntermediateDumpWriter::ScopedArrayMap modules(writer); if (image_infos->dyldPath) { - WriteProperty(writer, - IntermediateDumpKey::kName, - image_infos->dyldPath, - strlen(image_infos->dyldPath)); + WritePropertyCString( + writer, IntermediateDumpKey::kName, PATH_MAX, image_infos->dyldPath); } uint64_t address = FromPointerCast(image_infos->dyldImageLoadAddress); @@ -1129,10 +1065,6 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress( // Make sure that the basic load command structure doesn’t overflow the // space allotted for load commands, as well as iterating through ncmds. vm_size_t slide = 0; - const symtab_command* symtab_command = nullptr; - const dysymtab_command* dysymtab_command = nullptr; - const segment_command_64* linkedit_seg = nullptr; - const segment_command_64* text_seg = nullptr; for (uint32_t cmd_index = 0, cumulative_cmd_size = 0; cmd_index <= header->ncmds && cumulative_cmd_size < header->sizeofcmds; ++cmd_index, cumulative_cmd_size += command->cmdsize) { @@ -1145,20 +1077,11 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress( const segment_command_64* segment_ptr = reinterpret_cast(command_ptr); if (strcmp(segment->segname, SEG_TEXT) == 0) { - text_seg = segment_ptr; WriteProperty(writer, IntermediateDumpKey::kSize, &segment->vmsize); slide = address - segment->vmaddr; } else if (strcmp(segment->segname, SEG_DATA) == 0) { WriteDataSegmentAnnotations(writer, segment_ptr, slide); - } else if (strcmp(segment->segname, SEG_LINKEDIT) == 0) { - linkedit_seg = segment_ptr; } - } else if (command->cmd == LC_SYMTAB) { - symtab_command = - reinterpret_cast(command_ptr); - } else if (command->cmd == LC_DYSYMTAB) { - dysymtab_command = - reinterpret_cast(command_ptr); } else if (command->cmd == LC_ID_DYLIB) { ScopedVMRead dylib; if (!dylib.Read(command_ptr)) { @@ -1195,16 +1118,6 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress( } WriteProperty(writer, IntermediateDumpKey::kFileType, &header->filetype); - - if (is_dyld && header->filetype == MH_DYLINKER) { - WriteDyldErrorStringAnnotation(writer, - address, - symtab_command, - dysymtab_command, - text_seg, - linkedit_seg, - slide); - } } void InProcessIntermediateDumpHandler::WriteDataSegmentAnnotations( @@ -1286,12 +1199,10 @@ void InProcessIntermediateDumpHandler::WriteCrashpadAnnotationsList( } IOSIntermediateDumpWriter::ScopedArrayMap annotation_map(writer); - const size_t name_len = strnlen(reinterpret_cast(node->name()), - Annotation::kNameMaxLength); - WritePropertyBytes(writer, - IntermediateDumpKey::kAnnotationName, - reinterpret_cast(node->name()), - name_len); + WritePropertyCString(writer, + IntermediateDumpKey::kAnnotationName, + Annotation::kNameMaxLength, + reinterpret_cast(node->name())); WritePropertyBytes(writer, IntermediateDumpKey::kAnnotationValue, reinterpret_cast(node->value()), diff --git a/util/ios/ios_intermediate_dump_writer.cc b/util/ios/ios_intermediate_dump_writer.cc index 0fd3851697..bfbb596c2d 100644 --- a/util/ios/ios_intermediate_dump_writer.cc +++ b/util/ios/ios_intermediate_dump_writer.cc @@ -15,8 +15,10 @@ #include "util/ios/ios_intermediate_dump_writer.h" #include +#include #include +#include #include #include "base/check.h" @@ -86,6 +88,73 @@ bool IOSIntermediateDumpWriter::Close() { return RawLoggingCloseFile(fd); } +bool IOSIntermediateDumpWriter::AddPropertyCString(IntermediateDumpKey key, + size_t max_length, + const char* value) { + constexpr size_t kMaxStringBytes = 1024; + if (max_length > kMaxStringBytes) { + CRASHPAD_RAW_LOG("AddPropertyCString max_length too large"); + return false; + } + + char buffer[kMaxStringBytes]; + size_t string_length; + if (ReadCStringInternal(value, buffer, max_length, &string_length)) { + return Property(key, buffer, string_length); + } + return false; +} + +bool IOSIntermediateDumpWriter::ReadCStringInternal(const char* value, + char* buffer, + size_t max_length, + size_t* string_length) { + size_t length = 0; + while (length < max_length) { + vm_address_t data_address = reinterpret_cast(value + length); + // Calculate bytes to read past `data_address`, either the number of bytes + // to the end of the page, or the remaining bytes in `buffer`, whichever is + // smaller. + size_t data_to_end_of_page = + getpagesize() - (data_address - trunc_page(data_address)); + size_t remaining_bytes_in_buffer = max_length - length; + size_t bytes_to_read = + std::min(data_to_end_of_page, remaining_bytes_in_buffer); + + char* buffer_start = buffer + length; + size_t bytes_read = 0; + kern_return_t kr = + vm_read_overwrite(mach_task_self(), + data_address, + bytes_to_read, + reinterpret_cast(buffer_start), + &bytes_read); + if (kr != KERN_SUCCESS || bytes_read <= 0) { + CRASHPAD_RAW_LOG("ReadCStringInternal vm_read_overwrite failed"); + return false; + } + + char* nul = static_cast(memchr(buffer_start, '\0', bytes_read)); + if (nul != nullptr) { + length += nul - buffer_start; + *string_length = length; + return true; + } + length += bytes_read; + } + CRASHPAD_RAW_LOG("unterminated string"); + return false; +} + +bool IOSIntermediateDumpWriter::AddPropertyInternal(IntermediateDumpKey key, + const char* value, + size_t value_length) { + ScopedVMRead vmread; + if (!vmread.Read(value, value_length)) + return false; + return Property(key, vmread.get(), value_length); +} + bool IOSIntermediateDumpWriter::ArrayMapStart() { const CommandType command_type = CommandType::kMapStart; return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); @@ -123,17 +192,14 @@ bool IOSIntermediateDumpWriter::RootMapEnd() { return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); } -bool IOSIntermediateDumpWriter::AddPropertyInternal(IntermediateDumpKey key, - const char* value, - size_t value_length) { - ScopedVMRead vmread; - if (!vmread.Read(value, value_length)) - return false; +bool IOSIntermediateDumpWriter::Property(IntermediateDumpKey key, + const void* value, + size_t value_length) { const CommandType command_type = CommandType::kProperty; return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)) && RawLoggingWriteFile(fd_, &key, sizeof(key)) && RawLoggingWriteFile(fd_, &value_length, sizeof(size_t)) && - RawLoggingWriteFile(fd_, vmread.get(), value_length); + RawLoggingWriteFile(fd_, value, value_length); } } // namespace internal diff --git a/util/ios/ios_intermediate_dump_writer.h b/util/ios/ios_intermediate_dump_writer.h index d4f7a7b770..ea178353ed 100644 --- a/util/ios/ios_intermediate_dump_writer.h +++ b/util/ios/ios_intermediate_dump_writer.h @@ -175,9 +175,27 @@ class IOSIntermediateDumpWriter final { key, reinterpret_cast(value), value_length); } + //! \return Returns `true` if able to vm_read a string of \a value and write + //! a kProperty command with the \a key \a value up to a NUL byte. + //! The string cannot be longer than \a max_length with a maximum string + //! length of 1024. + bool AddPropertyCString(IntermediateDumpKey key, + size_t max_length, + const char* value); + private: - //! \return Returns `true` if able to write a kProperty command with the - //! \a key \a value \a count tuple. + //! \return Returns `true` if able to vm_read_overwrite \a value into + //! \a buffer while only reading one page at a time up to a NUL byte. + //! Sets the final length of \a buffer to \a string_length. + //! Returns `false` if unable to vm_read \a value or when no NUL byte can + //! be found within /a max_length (unterminated). + bool ReadCStringInternal(const char* value, + char* buffer, + size_t max_length, + size_t* string_length); + + //! \return Returns `true` if able to vm_read \a value \a count and write a + //! kProperty command with the \a key \a value \a count tuple. bool AddPropertyInternal(IntermediateDumpKey key, const char* value, size_t value_length); @@ -205,6 +223,12 @@ class IOSIntermediateDumpWriter final { //! \return Returns `true` if able to write a kRootMapEnd command. bool RootMapEnd(); + //! \return Returns `true` if able to write a kProperty command with the + //! \a key \a value \a value_length tuple. + bool Property(IntermediateDumpKey key, + const void* value, + size_t value_length); + int fd_; }; diff --git a/util/ios/ios_intermediate_dump_writer_test.cc b/util/ios/ios_intermediate_dump_writer_test.cc index 055ae70cca..5e70899625 100644 --- a/util/ios/ios_intermediate_dump_writer_test.cc +++ b/util/ios/ios_intermediate_dump_writer_test.cc @@ -15,8 +15,10 @@ #include "util/ios/ios_intermediate_dump_writer.h" #include +#include #include "base/files/scoped_file.h" +#include "base/mac/scoped_mach_vm.h" #include "base/posix/eintr_wrapper.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -102,6 +104,78 @@ TEST_F(IOSIntermediateDumpWriterTest, Property) { ASSERT_EQ(contents, result); } +TEST_F(IOSIntermediateDumpWriterTest, PropertyString) { + EXPECT_TRUE(writer_->Open(path())); + EXPECT_TRUE(writer_->AddPropertyCString(Key::kVersion, 64, "version")); + + std::string contents; + ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); + std::string result("\5\1\0\a\0\0\0\0\0\0\0version", 18); + ASSERT_EQ(contents, result); +} + +TEST_F(IOSIntermediateDumpWriterTest, PropertyStringShort) { + EXPECT_TRUE(writer_->Open(path())); + EXPECT_FALSE( + writer_->AddPropertyCString(Key::kVersion, 7, "versionnnnnnnnnnnn")); +} + +TEST_F(IOSIntermediateDumpWriterTest, PropertyStringLong) { + EXPECT_TRUE(writer_->Open(path())); + + char* bad_string = nullptr; + EXPECT_FALSE(writer_->AddPropertyCString(Key::kVersion, 1025, bad_string)); +} + +TEST_F(IOSIntermediateDumpWriterTest, MissingPropertyString) { + char* region; + vm_size_t page_size = getpagesize(); + vm_size_t region_size = page_size * 2; + ASSERT_EQ(vm_allocate(mach_task_self(), + reinterpret_cast(®ion), + region_size, + VM_FLAGS_ANYWHERE), + 0); + base::mac::ScopedMachVM vm_owner(reinterpret_cast(region), + region_size); + + // Fill first page with 'A' and second with 'B'. + memset(region, 'A', page_size); + memset(region + page_size, 'B', page_size); + + // Drop a NUL 10 bytes from the end of the first page and into the second + // page. + region[page_size - 10] = '\0'; + region[page_size + 10] = '\0'; + + // Read a string that spans two pages. + EXPECT_TRUE(writer_->Open(path())); + EXPECT_TRUE( + writer_->AddPropertyCString(Key::kVersion, 64, region + page_size - 5)); + std::string contents; + ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); + std::string result("\x5\x1\0\xF\0\0\0\0\0\0\0AAAAABBBBBBBBBB", 26); + ASSERT_EQ(contents, result); + + // Dealloc second page. + ASSERT_EQ(vm_deallocate(mach_task_self(), + reinterpret_cast(region + page_size), + page_size), + 0); + + // Reading the same string should fail when the next page is dealloc-ed. + EXPECT_FALSE( + writer_->AddPropertyCString(Key::kVersion, 64, region + page_size - 5)); + + // Ensure we can read the first string without loading the second page. + EXPECT_TRUE(writer_->Open(path())); + EXPECT_TRUE( + writer_->AddPropertyCString(Key::kVersion, 64, region + page_size - 20)); + ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); + result.assign("\x5\x1\0\n\0\0\0\0\0\0\0AAAAAAAAAA", 21); + ASSERT_EQ(contents, result); +} + TEST_F(IOSIntermediateDumpWriterTest, BadProperty) { EXPECT_TRUE(writer_->Open(path())); ASSERT_FALSE(writer_->AddProperty(Key::kVersion, "version", -1)); From df86075acc33314e611b351b33bf1c671b8cbc2f Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 14 Jul 2022 11:00:29 -0400 Subject: [PATCH 204/478] ios: Prevent duplicate uploads and watchdog kills with slow uploads. On iOS, holding a lock during a slow upload can lead to watchdog kills if the app is suspended mid-upload. Instead, if the client can obtain the lock, the database sets a lock-time file attribute and releases the flock. The file attribute is cleared when the upload is completed. The lock-time attribute can be used to prevent file access from other processes, or to discard reports that likely were terminated mid-upload. Bug:chromium:1342051 Change-Id: Ib878f6ade8eae467ee39acb52288296759c84582 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3739019 Reviewed-by: Robert Sesek Commit-Queue: Justin Cohen Reviewed-by: Mark Mentovai --- client/crash_report_database.h | 10 ++++- client/crash_report_database_mac.mm | 58 ++++++++++++++++++++++++++- client/crash_report_database_test.cc | 44 ++++++++++++++++++++ client/settings.h | 8 ++++ handler/crash_report_upload_thread.cc | 8 +--- util/misc/metrics.cc | 7 ++++ util/misc/metrics.h | 6 +++ util/net/http_transport_mac.mm | 2 + 8 files changed, 134 insertions(+), 9 deletions(-) diff --git a/client/crash_report_database.h b/client/crash_report_database.h index fea49853a0..4404959fad 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -328,7 +328,8 @@ class CrashReportDatabase { virtual OperationStatus GetCompletedReports(std::vector* reports) = 0; //! \brief Obtains and locks a report object for uploading to a collection - //! server. + //! server. On iOS the file lock is released and mutual-exclusion is kept + //! via a file attribute. //! //! Callers should upload the crash report using the FileReader provided. //! Callers should then call RecordUploadComplete() to record a successful @@ -336,6 +337,13 @@ class CrashReportDatabase { //! be recorded as unsuccessful and the report lock released when \a report is //! destroyed. //! + //! On iOS, holding a lock during a slow upload can lead to watchdog kills if + //! the app is suspended mid-upload. Instead, if the client can obtain the + //! lock, the database sets a lock-time file attribute and releases the lock. + //! The attribute is cleared when the upload is completed. The lock-time + //! attribute can be used to prevent file access from other processes, or to + //! discard reports that likely were terminated mid-upload. + //! //! \param[in] uuid The unique identifier for the crash report record. //! \param[out] report A crash report record for the report to be uploaded. //! Only valid if this returns #kNoError. diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index e33b932528..813e5b8fb9 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -71,6 +71,9 @@ constexpr char kXattrCollectorID[] = "id"; constexpr char kXattrCreationTime[] = "creation_time"; constexpr char kXattrIsUploaded[] = "uploaded"; +#if BUILDFLAG(IS_IOS) +constexpr char kXattrUploadStartTime[] = "upload_start_time"; +#endif constexpr char kXattrLastUploadTime[] = "last_upload_time"; constexpr char kXattrUploadAttemptCount[] = "upload_count"; constexpr char kXattrIsUploadExplicitlyRequested[] = @@ -189,10 +192,11 @@ OperationStatus RecordUploadAttempt(UploadReport* report, //! \brief Obtain a background task assertion while a flock is in use. //! Ensure this is defined first so it is destroyed last. internal::ScopedBackgroundTask ios_background_task{"UploadReportMac"}; -#endif // BUILDFLAG(IS_IOS) +#else //! \brief Stores the flock of the file for the duration of //! GetReportForUploading() and RecordUploadAttempt(). base::ScopedFD lock_fd; +#endif // BUILDFLAG(IS_IOS) }; //! \brief Locates a crash report in the database by UUID. @@ -474,12 +478,50 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, if (!ReadReportMetadataLocked(upload_report->file_path, upload_report.get())) return kDatabaseError; +#if BUILDFLAG(IS_IOS) + time_t upload_start_time = 0; + if (ReadXattrTimeT(upload_report->file_path, + XattrName(kXattrUploadStartTime), + &upload_start_time) == XattrStatus::kOtherError) { + return kDatabaseError; + } + + time_t now = time(nullptr); + if (upload_start_time) { + // If we were able to ObtainReportLock but kXattrUploadStartTime is set, + // either another client is uploading this report or a client was terminated + // during an upload. CrashReportUploadThread sets the timeout to 20 seconds + // for iOS. If kXattrUploadStartTime is less than 5 minutes ago, consider + // the report locked and return kBusyError. Otherwise, consider the upload a + // failure and skip the report. + if (upload_start_time > now - 15 * internal::kUploadReportTimeoutSeconds) { + return kBusyError; + } else { + // SkipReportUpload expects an unlocked report. + lock.reset(); + CrashReportDatabase::OperationStatus os = SkipReportUpload( + upload_report->uuid, Metrics::CrashSkippedReason::kUploadFailed); + if (os != kNoError) { + return kDatabaseError; + } + return kReportNotFound; + } + } + + if (!WriteXattrTimeT( + upload_report->file_path, XattrName(kXattrUploadStartTime), now)) { + return kDatabaseError; + } +#endif + if (!upload_report->Initialize(upload_report->file_path, this)) { return kFileSystemError; } upload_report->database_ = this; +#if !BUILDFLAG(IS_IOS) upload_report->lock_fd.reset(lock.release()); +#endif upload_report->report_metrics_ = report_metrics; report->reset(upload_report.release()); return kNoError; @@ -510,6 +552,13 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, return os; } +#if BUILDFLAG(IS_IOS) + if (RemoveXattr(report_path, XattrName(kXattrUploadStartTime)) == + XattrStatus::kOtherError) { + return kDatabaseError; + } +#endif + if (!WriteXattrBool(report_path, XattrName(kXattrIsUploaded), successful)) { return kDatabaseError; } @@ -554,6 +603,13 @@ OperationStatus ReportsInDirectory(const base::FilePath& path, if (!lock.is_valid()) return kBusyError; +#if BUILDFLAG(IS_IOS) + if (RemoveXattr(report_path, XattrName(kXattrUploadStartTime)) == + XattrStatus::kOtherError) { + return kDatabaseError; + } +#endif + return MarkReportCompletedLocked(report_path, nullptr); } diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index bdb6dc242c..67b5edcc2c 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -24,6 +24,10 @@ #include "util/file/file_io.h" #include "util/file/filesystem.h" +#if BUILDFLAG(IS_IOS) +#include "util/mac/xattr.h" +#endif + namespace crashpad { namespace test { namespace { @@ -511,6 +515,46 @@ TEST_F(CrashReportDatabaseTest, DuelingUploads) { CrashReportDatabase::kNoError); } +#if BUILDFLAG(IS_IOS) +TEST_F(CrashReportDatabaseTest, InterruptedIOSUploads) { + CrashReportDatabase::Report report; + CreateCrashReport(&report); + + std::unique_ptr upload_report; + EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report), + CrashReportDatabase::kNoError); + + // Set upload_start_time to 10 minutes ago. + time_t ten_minutes_ago = time(nullptr) - 10 * 60; + ASSERT_TRUE( + WriteXattrTimeT(report.file_path, + "org.chromium.crashpad.database.upload_start_time", + ten_minutes_ago)); + + std::vector reports; + EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError); + ASSERT_EQ(reports.size(), 1u); + reports.clear(); + EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError); + EXPECT_TRUE(reports.empty()); + + // Getting a stale report will automatically skip it. + std::unique_ptr upload_report_2; + EXPECT_EQ(db()->GetReportForUploading(report.uuid, &upload_report_2), + CrashReportDatabase::kReportNotFound); + EXPECT_FALSE(upload_report_2); + + // Confirm report was moved from pending to completed. + EXPECT_EQ(db()->GetPendingReports(&reports), CrashReportDatabase::kNoError); + EXPECT_TRUE(reports.empty()); + EXPECT_EQ(db()->GetCompletedReports(&reports), CrashReportDatabase::kNoError); + ASSERT_EQ(reports.size(), 1u); + + EXPECT_EQ(db()->RecordUploadComplete(std::move(upload_report), std::string()), + CrashReportDatabase::kReportNotFound); +} +#endif + TEST_F(CrashReportDatabaseTest, UploadAlreadyUploaded) { CrashReportDatabase::Report report; CreateCrashReport(&report); diff --git a/client/settings.h b/client/settings.h index 8ad8a2b16f..e4a5cedc43 100644 --- a/client/settings.h +++ b/client/settings.h @@ -37,6 +37,14 @@ struct ScopedLockedFileHandleTraits { static void Free(FileHandle handle); }; +// TODO(mark): The timeout should be configurable by the client. +#if BUILDFLAG(IS_IOS) +// iOS background assertions only last 30 seconds, keep the timeout shorter. +constexpr double kUploadReportTimeoutSeconds = 20; +#else +constexpr double kUploadReportTimeoutSeconds = 60; +#endif + } // namespace internal //! \brief An interface for accessing and modifying the settings of a diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index 138cf80026..4d1548dbf8 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -311,13 +311,7 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport( } http_transport->SetBodyStream(http_multipart_builder.GetBodyStream()); // TODO(mark): The timeout should be configurable by the client. -#if BUILDFLAG(IS_IOS) - // iOS background assertions only last 30 seconds, keep the timeout shorter. - double timeout_seconds = 20; -#else - double timeout_seconds = 60; -#endif - http_transport->SetTimeout(timeout_seconds); + http_transport->SetTimeout(internal::kUploadReportTimeoutSeconds); std::string url = url_; if (options_.identify_client_via_url) { diff --git a/util/misc/metrics.cc b/util/misc/metrics.cc index 2e8459c71d..dac7300d5d 100644 --- a/util/misc/metrics.cc +++ b/util/misc/metrics.cc @@ -78,6 +78,13 @@ void Metrics::CrashUploadAttempted(bool successful) { UMA_HISTOGRAM_BOOLEAN("Crashpad.CrashUpload.AttemptSuccessful", successful); } +#if BUILDFLAG(IS_APPLE) +// static +void Metrics::CrashUploadErrorCode(int error_code) { + base::UmaHistogramSparse("Crashpad.CrashUpload.ErrorCode", error_code); +} +#endif + // static void Metrics::CrashUploadSkipped(CrashSkippedReason reason) { UMA_HISTOGRAM_ENUMERATION( diff --git a/util/misc/metrics.h b/util/misc/metrics.h index c870b3a22a..e11fcc1303 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -63,6 +63,12 @@ class Metrics { //! \brief Reports on a crash upload attempt, and if it succeeded. static void CrashUploadAttempted(bool successful); +#if BUILDFLAG(IS_APPLE) || DOXYGEN + //! \brief Records error codes from + //! `+[NSURLConnection sendSynchronousRequest:returningResponse:error:]`. + static void CrashUploadErrorCode(int error_code); +#endif + //! \brief Values for CrashUploadSkipped(). //! //! \note These are used as metrics enumeration values, so new values should diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm index 50b9206880..445e895d13 100644 --- a/util/net/http_transport_mac.mm +++ b/util/net/http_transport_mac.mm @@ -25,6 +25,7 @@ #include "package.h" #include "util/file/file_io.h" #include "util/misc/implicit_cast.h" +#include "util/misc/metrics.h" #include "util/net/http_body.h" // An implementation of NSInputStream that reads from a @@ -257,6 +258,7 @@ - (BOOL)setProperty:(id)property forKey:(NSStreamPropertyKey)key { #pragma clang diagnostic pop if (error) { + Metrics::CrashUploadErrorCode(error.code); LOG(ERROR) << [[error localizedDescription] UTF8String] << " (" << [[error domain] UTF8String] << " " << [error code] << ")"; return false; From ae7d8a9ba461134ae8eb7f7a86dfc02bb41a85d6 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 15 Jul 2022 14:36:38 -0400 Subject: [PATCH 205/478] ios: Use fewer vm_reads when iterating modules. Rather than vm_reading each individual module load_command, load all of the commands at once. This saves nearly 200ms on an iPhone 12 Pro. Change-Id: I06f56c3ecbdf74f78759648ea62bcccd027f304c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3764242 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- .../in_process_intermediate_dump_handler.cc | 123 ++++++++---------- .../in_process_intermediate_dump_handler.h | 10 +- 2 files changed, 61 insertions(+), 72 deletions(-) diff --git a/client/ios_handler/in_process_intermediate_dump_handler.cc b/client/ios_handler/in_process_intermediate_dump_handler.cc index 6b431581d2..93128931d1 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -1053,68 +1053,63 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress( return; } - const load_command* command_ptr = reinterpret_cast( - reinterpret_cast(address) + 1); - - ScopedVMRead command; - if (!command.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid module command"); + const load_command* unsafe_command_ptr = + reinterpret_cast( + reinterpret_cast(address) + 1); + + // Rather than using an individual ScopedVMRead for each load_command, load + // the entire block of commands at once. + ScopedVMRead all_commands; + if (!all_commands.Read(unsafe_command_ptr, header->sizeofcmds)) { + CRASHPAD_RAW_LOG("Unable to read module load_commands."); return; } + // All the *_vm_read_ptr variables in the load_command loop below have been + // vm_read in `all_commands` above, and may be dereferenced without additional + // ScopedVMReads. + const load_command* command_vm_read_ptr = + reinterpret_cast(all_commands.get()); + // Make sure that the basic load command structure doesn’t overflow the // space allotted for load commands, as well as iterating through ncmds. vm_size_t slide = 0; for (uint32_t cmd_index = 0, cumulative_cmd_size = 0; - cmd_index <= header->ncmds && cumulative_cmd_size < header->sizeofcmds; - ++cmd_index, cumulative_cmd_size += command->cmdsize) { - if (command->cmd == LC_SEGMENT_64) { - ScopedVMRead segment; - if (!segment.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid LC_SEGMENT_64 segment"); - return; - } - const segment_command_64* segment_ptr = - reinterpret_cast(command_ptr); - if (strcmp(segment->segname, SEG_TEXT) == 0) { - WriteProperty(writer, IntermediateDumpKey::kSize, &segment->vmsize); - slide = address - segment->vmaddr; - } else if (strcmp(segment->segname, SEG_DATA) == 0) { - WriteDataSegmentAnnotations(writer, segment_ptr, slide); - } - } else if (command->cmd == LC_ID_DYLIB) { - ScopedVMRead dylib; - if (!dylib.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid LC_ID_DYLIB segment"); - return; + cmd_index < header->ncmds && cumulative_cmd_size < header->sizeofcmds; + ++cmd_index) { + if (command_vm_read_ptr->cmd == LC_SEGMENT_64) { + const segment_command_64* segment_vm_read_ptr = + reinterpret_cast(command_vm_read_ptr); + if (strcmp(segment_vm_read_ptr->segname, SEG_TEXT) == 0) { + WriteProperty( + writer, IntermediateDumpKey::kSize, &segment_vm_read_ptr->vmsize); + slide = address - segment_vm_read_ptr->vmaddr; + } else if (strcmp(segment_vm_read_ptr->segname, SEG_DATA) == 0) { + WriteDataSegmentAnnotations(writer, segment_vm_read_ptr, slide); } + } else if (command_vm_read_ptr->cmd == LC_ID_DYLIB) { + const dylib_command* dylib_vm_read_ptr = + reinterpret_cast(command_vm_read_ptr); WriteProperty(writer, IntermediateDumpKey::kDylibCurrentVersion, - &dylib->dylib.current_version); - } else if (command->cmd == LC_SOURCE_VERSION) { - ScopedVMRead source_version; - if (!source_version.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid LC_SOURCE_VERSION segment"); - return; - } + &dylib_vm_read_ptr->dylib.current_version); + } else if (command_vm_read_ptr->cmd == LC_SOURCE_VERSION) { + const source_version_command* source_version_vm_read_ptr = + reinterpret_cast(command_vm_read_ptr); WriteProperty(writer, IntermediateDumpKey::kSourceVersion, - &source_version->version); - } else if (command->cmd == LC_UUID) { - ScopedVMRead uuid; - if (!uuid.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid LC_UUID segment"); - return; - } - WriteProperty(writer, IntermediateDumpKey::kUUID, &uuid->uuid); + &source_version_vm_read_ptr->version); + } else if (command_vm_read_ptr->cmd == LC_UUID) { + const uuid_command* uuid_vm_read_ptr = + reinterpret_cast(command_vm_read_ptr); + WriteProperty( + writer, IntermediateDumpKey::kUUID, &uuid_vm_read_ptr->uuid); } - command_ptr = reinterpret_cast( - reinterpret_cast(command_ptr) + command->cmdsize); - if (!command.Read(command_ptr)) { - CRASHPAD_RAW_LOG("Invalid module command"); - return; - } + cumulative_cmd_size += command_vm_read_ptr->cmdsize; + command_vm_read_ptr = reinterpret_cast( + reinterpret_cast(command_vm_read_ptr) + + command_vm_read_ptr->cmdsize); } WriteProperty(writer, IntermediateDumpKey::kFileType, &header->filetype); @@ -1122,40 +1117,32 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress( void InProcessIntermediateDumpHandler::WriteDataSegmentAnnotations( IOSIntermediateDumpWriter* writer, - const segment_command_64* segment_ptr, + const segment_command_64* segment_vm_read_ptr, vm_size_t slide) { - ScopedVMRead segment; - if (!segment.Read(segment_ptr)) { - CRASHPAD_RAW_LOG("Unable to read SEG_DATA."); - return; - } - const section_64* section_ptr = reinterpret_cast( - reinterpret_cast(segment_ptr) + sizeof(segment_command_64)); - for (uint32_t sect_index = 0; sect_index <= segment->nsects; ++sect_index) { - ScopedVMRead section; - if (!section.Read(section_ptr)) { - CRASHPAD_RAW_LOG("Unable to read SEG_DATA section."); - return; - } - if (strcmp(section->sectname, "crashpad_info") == 0) { + const section_64* section_vm_read_ptr = reinterpret_cast( + reinterpret_cast(segment_vm_read_ptr) + + sizeof(segment_command_64)); + for (uint32_t sect_index = 0; sect_index <= segment_vm_read_ptr->nsects; + ++sect_index) { + if (strcmp(section_vm_read_ptr->sectname, "crashpad_info") == 0) { ScopedVMRead crashpad_info; - if (crashpad_info.Read(section->addr + slide) && + if (crashpad_info.Read(section_vm_read_ptr->addr + slide) && crashpad_info->size() == sizeof(CrashpadInfo) && crashpad_info->signature() == CrashpadInfo::kSignature && crashpad_info->version() == 1) { WriteCrashpadAnnotationsList(writer, crashpad_info.get()); WriteCrashpadSimpleAnnotationsDictionary(writer, crashpad_info.get()); } - } else if (strcmp(section->sectname, "__crash_info") == 0) { + } else if (strcmp(section_vm_read_ptr->sectname, "__crash_info") == 0) { ScopedVMRead crash_info; - if (!crash_info.Read(section->addr + slide) || + if (!crash_info.Read(section_vm_read_ptr->addr + slide) || (crash_info->version != 4 && crash_info->version != 5)) { continue; } WriteAppleCrashReporterAnnotations(writer, crash_info.get()); } - section_ptr = reinterpret_cast( - reinterpret_cast(section_ptr) + sizeof(section_64)); + section_vm_read_ptr = reinterpret_cast( + reinterpret_cast(section_vm_read_ptr) + sizeof(section_64)); } } diff --git a/client/ios_handler/in_process_intermediate_dump_handler.h b/client/ios_handler/in_process_intermediate_dump_handler.h index f6db28d510..49a520dc86 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler.h +++ b/client/ios_handler/in_process_intermediate_dump_handler.h @@ -139,10 +139,12 @@ class InProcessIntermediateDumpHandler final { bool is_dyld); //! \brief Extract and write Apple crashreporter_annotations_t data and - //! Crashpad annotations. - static void WriteDataSegmentAnnotations(IOSIntermediateDumpWriter* writer, - const segment_command_64* segment_ptr, - vm_size_t slide); + //! Crashpad annotations. Note that \a segment_vm_read_ptr has already + //! been read via vm_read and may be dereferenced without a ScopedVMRead. + static void WriteDataSegmentAnnotations( + IOSIntermediateDumpWriter* writer, + const segment_command_64* segment_vm_read_ptr, + vm_size_t slide); //! \brief Write Crashpad annotations list. static void WriteCrashpadAnnotationsList(IOSIntermediateDumpWriter* writer, From c25a4a77588e81d3c4ac09f89edeed587fa30a9a Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 18 Jul 2022 13:04:25 +0200 Subject: [PATCH 206/478] update submodules and add WER handler to CMake --- handler/CMakeLists.txt | 24 ++++++++++++++++++++++++ third_party/mini_chromium/mini_chromium | 2 +- util/CMakeLists.txt | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index 86dcdff9a3..fde7d26f64 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -122,3 +122,27 @@ if(NOT IOS) RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) endif() + +if(WIN32) + add_library(crashpad_wer SHARED + win/wer/crashpad_wer.cc + win/wer/crashpad_wer.h + win/wer/crashpad_wer.def + win/wer/crashpad_wer_main.cc + ../util/misc/address_types.h + ../util/win/address_types.h + ../util/win/registration_protocol_win.h + ) + + target_link_libraries(crashpad_wer + PRIVATE + $ + ) + + set_property(TARGET crashpad_wer PROPERTY EXPORT_NAME crashpad_wer) + add_library(crashpad::wer ALIAS crashpad_wer) + + install(TARGETS crashpad_wer EXPORT crashpad_export + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) +endif() diff --git a/third_party/mini_chromium/mini_chromium b/third_party/mini_chromium/mini_chromium index 5654edb422..75dcb8dc41 160000 --- a/third_party/mini_chromium/mini_chromium +++ b/third_party/mini_chromium/mini_chromium @@ -1 +1 @@ -Subproject commit 5654edb4225bcad13901155c819febb5748e502b +Subproject commit 75dcb8dc417af77fdb9ec23c7b51cb1d57dfcee2 diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index e37bfb155e..8a72636ff9 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -132,11 +132,11 @@ if(NOT WIN32) thread/thread_posix.cc posix/close_multiple.cc posix/close_multiple.h - posix/double_fork_and_exec.cc - posix/double_fork_and_exec.h posix/drop_privileges.cc posix/drop_privileges.h posix/process_info.h + posix/spawn_subprocess.cc + posix/spawn_subprocess.h posix/symbolic_constants_posix.cc posix/symbolic_constants_posix.h ) From fab4801e1e88772e97586c7eae8d1290a26f61ff Mon Sep 17 00:00:00 2001 From: Alex Pankhurst Date: Wed, 20 Jul 2022 10:36:27 -0700 Subject: [PATCH 207/478] [fuchsia] Fix ubsan issues Fuchsia's undefined behavior sanitizer was detecting unaligned accesses to 8 byte aligned data in Crashpad tests because various MINIDUMP_* structs are packed with 4 byte alignment. This change copies unaligned data in tests to local variable that can be safely used to check values. Example errors: ''' [../../third_party/crashpad/minidump/minidump_thread_name_list_writer_test.cc:95:3]: runtime error: reference binding to misaligned address 0x461e104cfbd4 for type 'const RVA64' (aka 'const unsigned long'), which requires 8 byte aligment ''' ''' ''' Change-Id: I3c0905aa9eab810c00d57f1e9e54bb8eaaff54b0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3775293 Reviewed-by: Joshua Peraza Commit-Queue: Alex Pankhurst --- .../minidump_thread_name_list_writer_test.cc | 13 +- minidump/minidump_writable_test.cc | 128 ++++++++++-------- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/minidump/minidump_thread_name_list_writer_test.cc b/minidump/minidump_thread_name_list_writer_test.cc index 265c12e684..43ed527028 100644 --- a/minidump/minidump_thread_name_list_writer_test.cc +++ b/minidump/minidump_thread_name_list_writer_test.cc @@ -91,10 +91,19 @@ void ExpectThreadName(const MINIDUMP_THREAD_NAME* expected, const MINIDUMP_THREAD_NAME* observed, const std::string& file_contents, const std::string& expected_thread_name) { + // Copy RvaOfThreadName into a local variable because + // |MINIDUMP_THREAD_NAME::RvaOfThreadName| requires 8-byte alignment but the + // struct itself is 4-byte algined. + const auto rva_of_thread_name = [&observed] { + RVA64 data = 0; + memcpy(&data, &observed->RvaOfThreadName, sizeof(RVA64)); + return data; + }(); + EXPECT_EQ(observed->ThreadId, expected->ThreadId); - EXPECT_NE(observed->RvaOfThreadName, 0u); + EXPECT_NE(rva_of_thread_name, 0u); const std::string observed_thread_name = base::UTF16ToUTF8( - MinidumpStringAtRVAAsString(file_contents, observed->RvaOfThreadName)); + MinidumpStringAtRVAAsString(file_contents, rva_of_thread_name)); EXPECT_EQ(observed_thread_name, expected_thread_name); } diff --git a/minidump/minidump_writable_test.cc b/minidump/minidump_writable_test.cc index 2032b06363..3d466d78e7 100644 --- a/minidump/minidump_writable_test.cc +++ b/minidump/minidump_writable_test.cc @@ -698,16 +698,25 @@ class TTestLocationDescriptorMinidumpWritable final template struct TLocationDescriptorAndData { MinidumpLocationDescriptorType location_descriptor; - char string[1]; + const char* string; }; template -const TLocationDescriptorAndData* TLDDAtIndex( - const std::string& string, +TLocationDescriptorAndData TLDDAtIndex( + const std::string& str, size_t index) { - return reinterpret_cast< - const TLocationDescriptorAndData*>( - &string[index]); + const MinidumpLocationDescriptorType* location_descriptor = + reinterpret_cast(&str[index]); + + const char* string = reinterpret_cast( + &str[index] + + offsetof(TLocationDescriptorAndData, + string)); + + return TLocationDescriptorAndData{ + *location_descriptor, + string, + }; } template @@ -746,9 +755,9 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 1); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + EXPECT_EQ(ldd.location_descriptor.DataSize, 0u); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); location_descriptor_writable.Verify(); } @@ -761,10 +770,10 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 1); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 1); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); location_descriptor_writable.Verify(); } @@ -778,11 +787,11 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { EXPECT_TRUE(location_descriptor_writable.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize + 3); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 3); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); - EXPECT_STREQ("zz", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); + EXPECT_STREQ("zz", ldd.string); location_descriptor_writable.Verify(); } @@ -800,17 +809,19 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize * 2 + 6); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 3); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); - EXPECT_STREQ("yy", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); + EXPECT_STREQ("yy", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); - EXPECT_EQ(ldd->location_descriptor.DataSize, + + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 2); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("x", ldd->string); + + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("x", ldd.string); parent.Verify(); } @@ -827,16 +838,18 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize * 2 + 7); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 3); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("www", ldd->string); + + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("www", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); - EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); - EXPECT_STREQ("vv", ldd->string); + + EXPECT_EQ(ldd.location_descriptor.DataSize, 0u); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); + EXPECT_STREQ("vv", ldd.string); parent.Verify(); } @@ -854,17 +867,16 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize * 2 + 13); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 5); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 8); - EXPECT_STREQ("uuuu", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 8); + EXPECT_STREQ("uuuu", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 8); - EXPECT_EQ(ldd->location_descriptor.DataSize, + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 5); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); - EXPECT_STREQ("tttt", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); + EXPECT_STREQ("tttt", ldd.string); parent.Verify(); } @@ -893,37 +905,33 @@ TYPED_TEST(MinidumpWritableLocationDescriptor, LocationDescriptor) { ASSERT_EQ(string_file.string().size(), kMinidumpLocationDescriptorSize * 5 + 18); - const LocationDescriptorAndData* ldd = LDDAtIndex(string_file.string(), 0); - EXPECT_EQ(ldd->location_descriptor.DataSize, + LocationDescriptorAndData ldd = LDDAtIndex(string_file.string(), 0); + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 2); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("s", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("s", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize + 4); - EXPECT_EQ(ldd->location_descriptor.DataSize, 0u); - EXPECT_EQ(ldd->location_descriptor.Rva, 0u); - EXPECT_STREQ("r", ldd->string); + EXPECT_EQ(ldd.location_descriptor.DataSize, 0u); + EXPECT_EQ(ldd.location_descriptor.Rva, 0u); + EXPECT_STREQ("r", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize * 2 + 8); - EXPECT_EQ(ldd->location_descriptor.DataSize, + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 2); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("q", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("q", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize * 3 + 12); - EXPECT_EQ(ldd->location_descriptor.DataSize, + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 2); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("p", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("p", ldd.string); ldd = LDDAtIndex(string_file.string(), kMinidumpLocationDescriptorSize * 4 + 16); - EXPECT_EQ(ldd->location_descriptor.DataSize, + EXPECT_EQ(ldd.location_descriptor.DataSize, kMinidumpLocationDescriptorSize + 2); - EXPECT_EQ(ldd->location_descriptor.Rva, - kMinidumpLocationDescriptorSize + 4); - EXPECT_STREQ("o", ldd->string); + EXPECT_EQ(ldd.location_descriptor.Rva, kMinidumpLocationDescriptorSize + 4); + EXPECT_STREQ("o", ldd.string); parent.Verify(); } } From 1b47570f6f4192f3effa9976529c9b81f66b06f0 Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Sun, 24 Jul 2022 12:09:07 -0400 Subject: [PATCH 208/478] ios: Add buffered write to IOSIntermediateDumpWriter. Adds a 4K buffer to the intermediate dump writer. Aside from the final flush, only write in multiples of 4K. This saves between 30ms and 50ms on an iPhone 12 Pro. Change-Id: Icc4b222477bd91fd6952c7cf43b105e1f7a50adb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3764243 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- ..._process_intermediate_dump_handler_test.cc | 35 +++---- ...ess_snapshot_ios_intermediate_dump_test.cc | 15 ++- util/ios/ios_intermediate_dump_writer.cc | 92 +++++++++++++++---- util/ios/ios_intermediate_dump_writer.h | 49 ++++++---- util/ios/ios_intermediate_dump_writer_test.cc | 16 ++-- 5 files changed, 147 insertions(+), 60 deletions(-) diff --git a/client/ios_handler/in_process_intermediate_dump_handler_test.cc b/client/ios_handler/in_process_intermediate_dump_handler_test.cc index f1d8a546a5..f89143ac82 100644 --- a/client/ios_handler/in_process_intermediate_dump_handler_test.cc +++ b/client/ios_handler/in_process_intermediate_dump_handler_test.cc @@ -55,15 +55,18 @@ class InProcessIntermediateDumpHandlerTest : public testing::Test { EXPECT_FALSE(IsRegularFile(path_)); } - void WriteReport() { - internal::IOSIntermediateDumpWriter::ScopedRootMap rootMap(writer_.get()); - InProcessIntermediateDumpHandler::WriteHeader(writer_.get()); - InProcessIntermediateDumpHandler::WriteProcessInfo( - writer_.get(), {{"before_dump", "pre"}}); - InProcessIntermediateDumpHandler::WriteSystemInfo(writer_.get(), - system_data_); - InProcessIntermediateDumpHandler::WriteThreadInfo(writer_.get(), 0, 0); - InProcessIntermediateDumpHandler::WriteModuleInfo(writer_.get()); + void WriteReportAndCloseWriter() { + { + internal::IOSIntermediateDumpWriter::ScopedRootMap rootMap(writer_.get()); + InProcessIntermediateDumpHandler::WriteHeader(writer_.get()); + InProcessIntermediateDumpHandler::WriteProcessInfo( + writer_.get(), {{"before_dump", "pre"}}); + InProcessIntermediateDumpHandler::WriteSystemInfo(writer_.get(), + system_data_); + InProcessIntermediateDumpHandler::WriteThreadInfo(writer_.get(), 0, 0); + InProcessIntermediateDumpHandler::WriteModuleInfo(writer_.get()); + } + EXPECT_TRUE(writer_->Close()); } void WriteMachException() { @@ -94,7 +97,7 @@ class InProcessIntermediateDumpHandlerTest : public testing::Test { }; TEST_F(InProcessIntermediateDumpHandlerTest, TestSystem) { - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); @@ -152,7 +155,7 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestAnnotations) { test_annotation_four.Set("same-name 4"); test_annotation_two.Clear(); - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath( path(), {{"after_dump", "post"}})); @@ -209,7 +212,7 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestAnnotations) { TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) { const ScopedSetThreadName scoped_set_thread_name("TestThreads"); - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); @@ -228,26 +231,26 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) { } TEST_F(InProcessIntermediateDumpHandlerTest, TestProcess) { - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); EXPECT_EQ(process_snapshot.ProcessID(), getpid()); } TEST_F(InProcessIntermediateDumpHandlerTest, TestMachException) { - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); } TEST_F(InProcessIntermediateDumpHandlerTest, TestSignalException) { - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); } TEST_F(InProcessIntermediateDumpHandlerTest, TestNSException) { - WriteReport(); + WriteReportAndCloseWriter(); internal::ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {})); } diff --git a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc index 0a170e7bf7..1ccb8b76b8 100644 --- a/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc +++ b/snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc @@ -63,7 +63,7 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { } void TearDown() override { - EXPECT_TRUE(writer_->Close()); + CloseWriter(); writer_.reset(); EXPECT_FALSE(IsRegularFile(path_)); } @@ -492,6 +492,8 @@ class ProcessSnapshotIOSIntermediateDumpTest : public testing::Test { ExpectMachException(*snapshot.Exception()); } + void CloseWriter() { EXPECT_TRUE(writer_->Close()); } + private: std::unique_ptr writer_; ScopedTempDir temp_dir_; @@ -523,6 +525,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, InitializeMinimumDump) { { IOSIntermediateDumpWriter::ScopedMap map(writer(), Key::kSystemInfo); } { IOSIntermediateDumpWriter::ScopedMap map(writer(), Key::kProcessInfo); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -536,6 +539,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, MissingSystemDump) { EXPECT_TRUE(writer()->AddProperty(Key::kVersion, &version)); { IOSIntermediateDumpWriter::ScopedMap map(writer(), Key::kProcessInfo); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_FALSE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -548,6 +552,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, MissingProcessDump) { EXPECT_TRUE(writer()->AddProperty(Key::kVersion, &version)); { IOSIntermediateDumpWriter::ScopedMap map(writer(), Key::kSystemInfo); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_FALSE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -573,6 +578,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, EmptySignalDump) { writer()->AddProperty(Key::kThreadID, &thread_id); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -599,6 +605,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, EmptyMachDump) { writer()->AddProperty(Key::kThreadID, &thread_id); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -625,6 +632,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, EmptyExceptionDump) { writer()->AddProperty(Key::kThreadID, &thread_id); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -655,6 +663,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, EmptyUncaughtNSExceptionDump) { Key::kThreadUncaughtNSExceptionFrames, frames, num_frames); } } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -673,6 +682,8 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, ShortContext) { writer(), /*has_module_path=*/false, /*use_long_annotations=*/false); WriteMachException(writer(), true /* short_context=true*/); } + CloseWriter(); + ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -694,6 +705,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, LongAnnotations) { writer(), /*has_module_path=*/false, /*use_long_annotations=*/true); WriteMachException(writer()); } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); @@ -715,6 +727,7 @@ TEST_F(ProcessSnapshotIOSIntermediateDumpTest, FullReport) { writer(), /*has_module_path=*/true, /*use_long_annotations=*/false); WriteMachException(writer()); } + CloseWriter(); ProcessSnapshotIOSIntermediateDump process_snapshot; ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), annotations())); EXPECT_FALSE(IsRegularFile(path())); diff --git a/util/ios/ios_intermediate_dump_writer.cc b/util/ios/ios_intermediate_dump_writer.cc index bfbb596c2d..9eeb6263fa 100644 --- a/util/ios/ios_intermediate_dump_writer.cc +++ b/util/ios/ios_intermediate_dump_writer.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -31,16 +32,15 @@ namespace crashpad { namespace internal { // Similar to LoggingWriteFile but with CRASHPAD_RAW_LOG. -bool RawLoggingWriteFile(int fd, const void* buffer, size_t size) { - uintptr_t buffer_int = reinterpret_cast(buffer); +bool RawLoggingWriteFile(int fd, const void* data, size_t size) { + const char* data_char = static_cast(data); while (size > 0) { - ssize_t bytes_written = HANDLE_EINTR( - write(fd, reinterpret_cast(buffer_int), size)); + ssize_t bytes_written = HANDLE_EINTR(write(fd, data_char, size)); if (bytes_written < 0 || bytes_written == 0) { CRASHPAD_RAW_LOG_ERROR(bytes_written, "RawLoggingWriteFile"); return false; } - buffer_int += bytes_written; + data_char += bytes_written; size -= bytes_written; } return true; @@ -56,7 +56,7 @@ bool RawLoggingCloseFile(int fd) { } IOSIntermediateDumpWriter::~IOSIntermediateDumpWriter() { - DCHECK_EQ(fd_, -1) << "Call Close() before this object is destroyed."; + CHECK_EQ(fd_, -1) << "Call Close() before this object is destroyed."; } bool IOSIntermediateDumpWriter::Open(const base::FilePath& path) { @@ -83,6 +83,9 @@ bool IOSIntermediateDumpWriter::Close() { if (fd_ < 0) { return true; } + if (!FlushWriteBuffer()) { + return false; + } int fd = fd_; fd_ = -1; return RawLoggingCloseFile(fd); @@ -157,49 +160,100 @@ bool IOSIntermediateDumpWriter::AddPropertyInternal(IntermediateDumpKey key, bool IOSIntermediateDumpWriter::ArrayMapStart() { const CommandType command_type = CommandType::kMapStart; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); + return BufferedWrite(&command_type, sizeof(command_type)); } bool IOSIntermediateDumpWriter::MapStart(IntermediateDumpKey key) { const CommandType command_type = CommandType::kMapStart; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)) && - RawLoggingWriteFile(fd_, &key, sizeof(key)); + return BufferedWrite(&command_type, sizeof(command_type)) && + BufferedWrite(&key, sizeof(key)); } bool IOSIntermediateDumpWriter::ArrayStart(IntermediateDumpKey key) { const CommandType command_type = CommandType::kArrayStart; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)) && - RawLoggingWriteFile(fd_, &key, sizeof(key)); + return BufferedWrite(&command_type, sizeof(command_type)) && + BufferedWrite(&key, sizeof(key)); } bool IOSIntermediateDumpWriter::MapEnd() { const CommandType command_type = CommandType::kMapEnd; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); + return BufferedWrite(&command_type, sizeof(command_type)); } bool IOSIntermediateDumpWriter::ArrayEnd() { const CommandType command_type = CommandType::kArrayEnd; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); + return BufferedWrite(&command_type, sizeof(command_type)); } bool IOSIntermediateDumpWriter::RootMapStart() { const CommandType command_type = CommandType::kRootMapStart; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); + return BufferedWrite(&command_type, sizeof(command_type)); } bool IOSIntermediateDumpWriter::RootMapEnd() { const CommandType command_type = CommandType::kRootMapEnd; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)); + return BufferedWrite(&command_type, sizeof(command_type)); } bool IOSIntermediateDumpWriter::Property(IntermediateDumpKey key, const void* value, size_t value_length) { const CommandType command_type = CommandType::kProperty; - return RawLoggingWriteFile(fd_, &command_type, sizeof(command_type)) && - RawLoggingWriteFile(fd_, &key, sizeof(key)) && - RawLoggingWriteFile(fd_, &value_length, sizeof(size_t)) && - RawLoggingWriteFile(fd_, value, value_length); + return BufferedWrite(&command_type, sizeof(command_type)) && + BufferedWrite(&key, sizeof(key)) && + BufferedWrite(&value_length, sizeof(size_t)) && + BufferedWrite(value, value_length); +} + +bool IOSIntermediateDumpWriter::FlushWriteBuffer() { + size_t size = buffer_occupied_; + buffer_occupied_ = 0; + return RawLoggingWriteFile(fd_, buffer_, size); +} + +bool IOSIntermediateDumpWriter::BufferedWrite(const void* data, + size_t data_size) { + const char* data_char = static_cast(data); + // If `buffer_` is occupied, fill it up first, and flush if full. + if (buffer_occupied_ > 0) { + size_t data_size_to_copy = + std::min(kBufferSize - buffer_occupied_, data_size); + memcpy(buffer_ + buffer_occupied_, data_char, data_size_to_copy); + buffer_occupied_ += data_size_to_copy; + data_char += data_size_to_copy; + data_size -= data_size_to_copy; + + if (buffer_occupied_ == kBufferSize) { + if (!FlushWriteBuffer()) { + return false; + } + } + } + + // Either `data_size` is big enough that it could fill `buffer_`, trigger + // a FlushWriteBuffer, and reset `buffer_occuppied_` to zero, or there is no + // data left to process. + DCHECK(buffer_occupied_ == 0 || data_size == 0); + + // Write the rest of the `data` in an increment of kBufferSize. + if (data_size >= kBufferSize) { + DCHECK_EQ(buffer_occupied_, 0u); + size_t data_size_to_write = data_size - (data_size % kBufferSize); + if (!RawLoggingWriteFile(fd_, data_char, data_size_to_write)) { + return false; + } + data_char += data_size_to_write; + data_size -= data_size_to_write; + } + + // If there's any `data` left, put it in `buffer_`. + if (data_size > 0) { + DCHECK_EQ(buffer_occupied_, 0u); + memcpy(buffer_, data_char, data_size); + buffer_occupied_ = data_size; + } + + return true; } } // namespace internal diff --git a/util/ios/ios_intermediate_dump_writer.h b/util/ios/ios_intermediate_dump_writer.h index ea178353ed..a11a4eb997 100644 --- a/util/ios/ios_intermediate_dump_writer.h +++ b/util/ios/ios_intermediate_dump_writer.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_UTIL_IOS_IOS_INTERMEDIATE_DUMP_WRITER_H_ #define CRASHPAD_UTIL_IOS_IOS_INTERMEDIATE_DUMP_WRITER_H_ +#include + #include "base/files/file_path.h" #include "util/ios/ios_intermediate_dump_format.h" @@ -39,7 +41,7 @@ namespace internal { //! Note: All methods are `RUNS-DURING-CRASH`. class IOSIntermediateDumpWriter final { public: - IOSIntermediateDumpWriter() : fd_(-1) { } + IOSIntermediateDumpWriter() : buffer_occupied_(0), fd_(-1) {} IOSIntermediateDumpWriter(const IOSIntermediateDumpWriter&) = delete; IOSIntermediateDumpWriter& operator=(const IOSIntermediateDumpWriter&) = @@ -175,8 +177,8 @@ class IOSIntermediateDumpWriter final { key, reinterpret_cast(value), value_length); } - //! \return Returns `true` if able to vm_read a string of \a value and write - //! a kProperty command with the \a key \a value up to a NUL byte. + //! \return `true` if able to vm_read a string of \a value and write a + //! kProperty command with the \a key \a value up to a NUL byte. //! The string cannot be longer than \a max_length with a maximum string //! length of 1024. bool AddPropertyCString(IntermediateDumpKey key, @@ -184,7 +186,7 @@ class IOSIntermediateDumpWriter final { const char* value); private: - //! \return Returns `true` if able to vm_read_overwrite \a value into + //! \return `true` if able to vm_read_overwrite \a value into //! \a buffer while only reading one page at a time up to a NUL byte. //! Sets the final length of \a buffer to \a string_length. //! Returns `false` if unable to vm_read \a value or when no NUL byte can @@ -194,41 +196,56 @@ class IOSIntermediateDumpWriter final { size_t max_length, size_t* string_length); - //! \return Returns `true` if able to vm_read \a value \a count and write a + //! \return `true` if able to vm_read \a value \a count and write a //! kProperty command with the \a key \a value \a count tuple. bool AddPropertyInternal(IntermediateDumpKey key, const char* value, size_t value_length); - //! \return Returns `true` if able to write a kArrayStart command with the - //! \a key. + //! \return `true` if able to write a kArrayStart command with the \a key. bool ArrayStart(IntermediateDumpKey key); - //! \return Returns `true` if able to write a kMapStart command with the - //! \a key. + //! \return `true` if able to write a kMapStart command with the \a key. bool MapStart(IntermediateDumpKey key); - //! \return Returns `true` if able to write a kMapStart command. + //! \return `true` if able to write a kMapStart command. bool ArrayMapStart(); - //! \return Returns `true` if able to write a kArrayEnd command. + //! \return `true` if able to write a kArrayEnd command. bool ArrayEnd(); - //! \return Returns `true` if able to write a kMapEnd command. + //! \return `true` if able to write a kMapEnd command. bool MapEnd(); - //! \return Returns `true` if able to write a kRootMapStart command. + //! \return `true` if able to write a kRootMapStart command. bool RootMapStart(); - //! \return Returns `true` if able to write a kRootMapEnd command. + //! \return `true` if able to write a kRootMapEnd command. bool RootMapEnd(); - //! \return Returns `true` if able to write a kProperty command with the - //! \a key \a value \a value_length tuple. + //! \return `true` if able to write a kProperty command with the \a key + //! \a value \a value_length tuple. bool Property(IntermediateDumpKey key, const void* value, size_t value_length); + //! \return `true` if able to write \a data up to \a size. The \a data might + //! not be written to fd_ until `buffer_` is full or the writer is + //! closed. All writes will be 4096 bytes (the size of your kBufferSize) + //! except for the final flush, which might be partial. + bool BufferedWrite(const void* data, size_t size); + + //! \return `true` if able to write `buffer_` up to `buffer_occupied_`. + bool FlushWriteBuffer(); + + //! \brief The maximum size of the write buffer. + static constexpr size_t kBufferSize = 4096; + + //! \brief The write data buffer and amount of that buffer occupied with data + //! to be written. + char buffer_[kBufferSize]; + size_t buffer_occupied_; + int fd_; }; diff --git a/util/ios/ios_intermediate_dump_writer_test.cc b/util/ios/ios_intermediate_dump_writer_test.cc index 5e70899625..0b56ed9e0d 100644 --- a/util/ios/ios_intermediate_dump_writer_test.cc +++ b/util/ios/ios_intermediate_dump_writer_test.cc @@ -74,6 +74,8 @@ TEST_F(IOSIntermediateDumpWriterTest, ScopedArray) { Key::kThreads); IOSIntermediateDumpWriter::ScopedArrayMap threadMap(writer_.get()); } + EXPECT_TRUE(writer_->Close()); + std::string contents; ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); std::string result("\6\x3p\x17\1\2\4\a", 8); @@ -87,6 +89,7 @@ TEST_F(IOSIntermediateDumpWriterTest, ScopedMap) { IOSIntermediateDumpWriter::ScopedMap map(writer_.get(), Key::kMachException); } + EXPECT_TRUE(writer_->Close()); std::string contents; ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); @@ -97,6 +100,7 @@ TEST_F(IOSIntermediateDumpWriterTest, ScopedMap) { TEST_F(IOSIntermediateDumpWriterTest, Property) { EXPECT_TRUE(writer_->Open(path())); EXPECT_TRUE(writer_->AddProperty(Key::kVersion, "version", 7)); + EXPECT_TRUE(writer_->Close()); std::string contents; ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); @@ -107,6 +111,7 @@ TEST_F(IOSIntermediateDumpWriterTest, Property) { TEST_F(IOSIntermediateDumpWriterTest, PropertyString) { EXPECT_TRUE(writer_->Open(path())); EXPECT_TRUE(writer_->AddPropertyCString(Key::kVersion, 64, "version")); + EXPECT_TRUE(writer_->Close()); std::string contents; ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); @@ -152,6 +157,7 @@ TEST_F(IOSIntermediateDumpWriterTest, MissingPropertyString) { EXPECT_TRUE(writer_->Open(path())); EXPECT_TRUE( writer_->AddPropertyCString(Key::kVersion, 64, region + page_size - 5)); + EXPECT_TRUE(writer_->Close()); std::string contents; ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); std::string result("\x5\x1\0\xF\0\0\0\0\0\0\0AAAAABBBBBBBBBB", 26); @@ -171,6 +177,7 @@ TEST_F(IOSIntermediateDumpWriterTest, MissingPropertyString) { EXPECT_TRUE(writer_->Open(path())); EXPECT_TRUE( writer_->AddPropertyCString(Key::kVersion, 64, region + page_size - 20)); + EXPECT_TRUE(writer_->Close()); ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); result.assign("\x5\x1\0\n\0\0\0\0\0\0\0AAAAAAAAAA", 21); ASSERT_EQ(contents, result); @@ -179,14 +186,7 @@ TEST_F(IOSIntermediateDumpWriterTest, MissingPropertyString) { TEST_F(IOSIntermediateDumpWriterTest, BadProperty) { EXPECT_TRUE(writer_->Open(path())); ASSERT_FALSE(writer_->AddProperty(Key::kVersion, "version", -1)); - - std::string contents; - ASSERT_TRUE(LoggingReadEntireFile(path(), &contents)); - - // path() is now invalid, as type, key and value were written, but the - // value itself is not. - std::string results("\5\1\0\xff\xff\xff\xff\xff\xff\xff\xff", 11); - ASSERT_EQ(contents, results); + EXPECT_TRUE(writer_->Close()); } } // namespace From bfc0eb5709b94133f26f8ce9c44589d7c58c685a Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Mon, 25 Jul 2022 12:47:53 -0700 Subject: [PATCH 209/478] Close handler_sock after starting crashpad server. handler_sock end of the socketpair is donated to the crashpad server process which owns it. The client should not keep it open. Otherwise if the crashpad server process crashes and the client is reading from client_sock, the client will hang forever because the other end is still open. This happens when: - /proc/sys/kernel/yama/ptrace_scope file is present. - crashpad is invoked with missing required fields, like --database. In this case, chrome hangs until timeout. Change-Id: I1776432d6d9fd44dc1c24e874a15fd6d2a376003 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3786896 Reviewed-by: Joshua Peraza Commit-Queue: Ayush Ranjan --- client/crashpad_client_linux.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 9cd452b577..6de50275f9 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -462,6 +462,7 @@ bool CrashpadClient::StartHandler( if (!SpawnSubprocess(argv, nullptr, handler_sock.get(), false, nullptr)) { return false; } + handler_sock.reset(); pid_t handler_pid = -1; if (!IsRegularFile(base::FilePath("/proc/sys/kernel/yama/ptrace_scope"))) { From 4e5cef683a547ff1ba8af2b3eccc8770659af620 Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Mon, 25 Jul 2022 20:00:27 -0700 Subject: [PATCH 210/478] Update documentation to use main branch name. Some documentation uses the old default branch name `master`. But `master` in crashpad repo is a very old branch and has been superseded with `main`. Change-Id: I368c829fde2d29b3f14aa14185bfc97d546bf340 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3787194 Reviewed-by: Mark Mentovai Commit-Queue: Mark Mentovai --- doc/appengine/src/crashpad-home/main.go | 30 ++++++++++++------------- doc/developing.md | 18 +++++++-------- doc/support/generate_git.sh | 12 +++++----- handler/crashpad_handler.md | 2 +- tools/base94_encoder.md | 2 +- tools/crashpad_database_util.md | 2 +- tools/crashpad_http_upload.md | 2 +- tools/generate_dump.md | 2 +- tools/mac/catch_exception_tool.md | 2 +- tools/mac/exception_port_tool.md | 2 +- tools/mac/on_demand_service_tool.md | 2 +- tools/run_with_crashpad.md | 2 +- 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/doc/appengine/src/crashpad-home/main.go b/doc/appengine/src/crashpad-home/main.go index 5ce7d0ab95..74830d426c 100644 --- a/doc/appengine/src/crashpad-home/main.go +++ b/doc/appengine/src/crashpad-home/main.go @@ -41,29 +41,29 @@ func init() { func handler(w http.ResponseWriter, r *http.Request) { const ( baseURL = "https://chromium.googlesource.com/crashpad/crashpad/+/" - masterBaseURL = baseURL + "master/" + mainBaseURL = baseURL + "main/" generatedDocBaseURL = baseURL + "doc/doc/generated/?format=TEXT" bugBaseURL = "https://bugs.chromium.org/p/crashpad/" ) redirectMap := map[string]string{ - "/": masterBaseURL + "README.md", + "/": mainBaseURL + "README.md", "/bug": bugBaseURL, "/bug/": bugBaseURL, "/bug/new": bugBaseURL + "issues/entry", - "/doc/developing.html": masterBaseURL + "/doc/developing.md", - "/doc/status.html": masterBaseURL + "/doc/status.md", - "/index.html": masterBaseURL + "README.md", - "/man": masterBaseURL + "doc/man.md", - "/man/": masterBaseURL + "doc/man.md", - "/man/catch_exception_tool.html": masterBaseURL + "tools/mac/catch_exception_tool.md", - "/man/crashpad_database_util.html": masterBaseURL + "tools/crashpad_database_util.md", - "/man/crashpad_handler.html": masterBaseURL + "handler/crashpad_handler.md", - "/man/exception_port_tool.html": masterBaseURL + "tools/mac/exception_port_tool.md", - "/man/generate_dump.html": masterBaseURL + "tools/generate_dump.md", - "/man/index.html": masterBaseURL + "doc/man.md", - "/man/on_demand_service_tool.html": masterBaseURL + "tools/mac/on_demand_service_tool.md", - "/man/run_with_crashpad.html": masterBaseURL + "tools/mac/run_with_crashpad.md", + "/doc/developing.html": mainBaseURL + "/doc/developing.md", + "/doc/status.html": mainBaseURL + "/doc/status.md", + "/index.html": mainBaseURL + "README.md", + "/man": mainBaseURL + "doc/man.md", + "/man/": mainBaseURL + "doc/man.md", + "/man/catch_exception_tool.html": mainBaseURL + "tools/mac/catch_exception_tool.md", + "/man/crashpad_database_util.html": mainBaseURL + "tools/crashpad_database_util.md", + "/man/crashpad_handler.html": mainBaseURL + "handler/crashpad_handler.md", + "/man/exception_port_tool.html": mainBaseURL + "tools/mac/exception_port_tool.md", + "/man/generate_dump.html": mainBaseURL + "tools/generate_dump.md", + "/man/index.html": mainBaseURL + "doc/man.md", + "/man/on_demand_service_tool.html": mainBaseURL + "tools/mac/on_demand_service_tool.md", + "/man/run_with_crashpad.html": mainBaseURL + "tools/mac/run_with_crashpad.md", } ctx := appengine.NewContext(r) diff --git a/doc/developing.md b/doc/developing.md index a4017fb787..06dec03e36 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -28,7 +28,7 @@ other projects, Crashpad uses [mini_chromium](https://chromium.googlesource.com/chromium/mini_chromium/), a small, self-contained library that provides many of Chromium’s useful low-level base routines. [mini_chromium’s -README](https://chromium.googlesource.com/chromium/mini_chromium/+/master/README.md) +README](https://chromium.googlesource.com/chromium/mini_chromium/+/main/README.md) provides more detail. ## Prerequisites @@ -153,7 +153,7 @@ suitable location. These instructions assume that it’s been expanded to Note that Chrome uses Android API level 21 for both 64-bit platforms and 32-bit platforms. See Chrome’s -[`build/config/android/config.gni`](https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni) +[`build/config/android/config.gni`](https://chromium.googlesource.com/chromium/src/+/main/build/config/android/config.gni) which sets `android32_ndk_api_level` and `android64_ndk_api_level`. Set these gn args @@ -241,7 +241,7 @@ $ ZIRCON_NODENAME=scare-brook-skip-dried python build/run_tests.py out/fuchsia ## Contributing Crashpad’s contribution process is very similar to [Chromium’s contribution -process](https://chromium.googlesource.com/chromium/src/+/master/docs/contributing.md). +process](https://chromium.googlesource.com/chromium/src/+/main/docs/contributing.md). ### Code Review @@ -250,7 +250,7 @@ review is conducted on [Chromium’s Gerrit](https://chromium-review.googlesource.com/) system, and all code reviews must be sent to an appropriate reviewer, with a Cc sent to [crashpad-dev](https://groups.google.com/a/chromium.org/group/crashpad-dev). The -[`codereview.settings`](https://chromium.googlesource.com/crashpad/crashpad/+/master/codereview.settings) +[`codereview.settings`](https://chromium.googlesource.com/crashpad/crashpad/+/main/codereview.settings) file specifies this environment to `git-cl`. `git-cl` is part of the @@ -259,7 +259,7 @@ no need to install it separately. ``` $ cd ~/crashpad/crashpad -$ git checkout -b work_branch origin/master +$ git checkout -b work_branch origin/main …do some work… $ git add … $ git commit @@ -280,7 +280,7 @@ patch set with `git cl upload` and let your reviewer know you’ve addressed the feedback. The most recently uploaded patch set on a review may be tested on a -[trybot](https://chromium.googlesource.com/chromium/src/+/master/docs/infra/trybot_usage.md) +[trybot](https://chromium.googlesource.com/chromium/src/+/main/docs/infra/trybot_usage.md) by running `git cl try` or by clicking the “CQ Dry Run” button in Gerrit. These set the “Commit-Queue: +1” label. This does not mean that the patch will be committed, but the trybot and commit queue share infrastructure and a Gerrit @@ -292,7 +292,7 @@ Crashpad and Chromium committers. After code review is complete and “Code-Review: +1” has been received from all reviewers, the patch can be submitted to Crashpad’s [commit -queue](https://chromium.googlesource.com/chromium/src/+/master/docs/infra/cq.md) +queue](https://chromium.googlesource.com/chromium/src/+/main/docs/infra/cq.md) by clicking the “Submit to CQ” button in Gerrit. This sets the “Commit-Queue: +2” label, which tests the patch on trybots before landing it. Commit queue access is available to Crashpad and Chromium committers. @@ -314,9 +314,9 @@ Agreement](https://cla.developers.google.com/about/google-individual) or [Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate) as appropriate before any submission can be accepted, and must be listed in the -[`AUTHORS`](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS) +[`AUTHORS`](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS) file. Contributors may be listed in the -[`CONTRIBUTORS`](https://chromium.googlesource.com/crashpad/crashpad/+/master/CONTRIBUTORS) +[`CONTRIBUTORS`](https://chromium.googlesource.com/crashpad/crashpad/+/main/CONTRIBUTORS) file. ## Buildbot diff --git a/doc/support/generate_git.sh b/doc/support/generate_git.sh index 209c11b95e..6a7c39f792 100755 --- a/doc/support/generate_git.sh +++ b/doc/support/generate_git.sh @@ -38,8 +38,8 @@ local_branch="\ $(${sed_ext} -e 's/(.*)\..*/\1/' <<< "${basename}").${$}.${RANDOM}" remote_name=origin -remote_master_branch_name=master -remote_master_branch="${remote_name}/${remote_master_branch_name}" +remote_main_branch_name=main +remote_main_branch="${remote_name}/${remote_main_branch_name}" remote_doc_branch_name=doc remote_doc_branch="${remote_name}/${remote_doc_branch_name}" @@ -61,9 +61,9 @@ function cleanup() { trap cleanup EXIT -master_hash=$(git rev-parse --short=12 "${remote_master_branch}") -git merge "${remote_master_branch}" \ - -m "Merge ${remote_master_branch_name} ${master_hash} into doc" +main_hash=$(git rev-parse --short=12 "${remote_main_branch}") +git merge "${remote_main_branch}" \ + -m "Merge ${remote_main_branch_name} ${main_hash} into doc" dirty=y @@ -74,7 +74,7 @@ git add -A doc/generated count="$(git diff --staged --numstat | wc -l)" if [[ $count -gt 0 ]]; then git commit \ - -m "Update documentation to ${remote_master_branch_name} ${master_hash}" + -m "Update documentation to ${remote_main_branch_name} ${main_hash}" dirty= git push "${remote_name}" "HEAD:${remote_doc_branch_name}" diff --git a/handler/crashpad_handler.md b/handler/crashpad_handler.md index 6d055ed175..30d4e687d9 100644 --- a/handler/crashpad_handler.md +++ b/handler/crashpad_handler.md @@ -332,7 +332,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/base94_encoder.md b/tools/base94_encoder.md index 292c7a63de..25f2ddde50 100644 --- a/tools/base94_encoder.md +++ b/tools/base94_encoder.md @@ -83,7 +83,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2020 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/crashpad_database_util.md b/tools/crashpad_database_util.md index a63d9a6803..d02b87091a 100644 --- a/tools/crashpad_database_util.md +++ b/tools/crashpad_database_util.md @@ -191,7 +191,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2015 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/crashpad_http_upload.md b/tools/crashpad_http_upload.md index 93b8752259..90a200e763 100644 --- a/tools/crashpad_http_upload.md +++ b/tools/crashpad_http_upload.md @@ -115,7 +115,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2017 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/generate_dump.md b/tools/generate_dump.md index c58ecbc3dc..0d10d11e8d 100644 --- a/tools/generate_dump.md +++ b/tools/generate_dump.md @@ -110,7 +110,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/mac/catch_exception_tool.md b/tools/mac/catch_exception_tool.md index 3c71decf63..699b0945d5 100644 --- a/tools/mac/catch_exception_tool.md +++ b/tools/mac/catch_exception_tool.md @@ -123,7 +123,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/mac/exception_port_tool.md b/tools/mac/exception_port_tool.md index 1743e42071..5a14e971dc 100644 --- a/tools/mac/exception_port_tool.md +++ b/tools/mac/exception_port_tool.md @@ -217,7 +217,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/mac/on_demand_service_tool.md b/tools/mac/on_demand_service_tool.md index 5a85035264..894f743417 100644 --- a/tools/mac/on_demand_service_tool.md +++ b/tools/mac/on_demand_service_tool.md @@ -116,7 +116,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License diff --git a/tools/run_with_crashpad.md b/tools/run_with_crashpad.md index 9758f9af8b..3aafea3b3d 100644 --- a/tools/run_with_crashpad.md +++ b/tools/run_with_crashpad.md @@ -130,7 +130,7 @@ Report bugs at https://crashpad.chromium.org/bug/new. ## Copyright Copyright 2014 [The Crashpad -Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/main/AUTHORS). ## License From 7b105f83ab3e644a6ffcb971df65803c18c61bff Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Thu, 28 Jul 2022 21:18:25 -0400 Subject: [PATCH 211/478] ios: Properly handle overflows in scoped_vm_read. Passing -1 (or size_t max) to ScopedVMRead would succeed, because the amount of memory to be read would overflow vm_address_t/vm_size_t and turn into something reasonable. ScopedVMRead would return true having only read a miniscule subset of the requested data length. Bug: 1348341 Change-Id: I061a1d86928f211c541a6378a78ee045d489a838 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3791710 Commit-Queue: Justin Cohen Reviewed-by: Mark Mentovai --- util/ios/scoped_vm_read.cc | 4 ++++ util/ios/scoped_vm_read_test.cc | 1 + 2 files changed, 5 insertions(+) diff --git a/util/ios/scoped_vm_read.cc b/util/ios/scoped_vm_read.cc index 06cf43440c..7ae85df74a 100644 --- a/util/ios/scoped_vm_read.cc +++ b/util/ios/scoped_vm_read.cc @@ -43,6 +43,10 @@ bool ScopedVMReadInternal::Read(const void* data, const size_t data_length) { vm_address_t page_region_address = trunc_page(data_address); vm_size_t page_region_size = round_page(data_address - page_region_address + data_length); + if (page_region_size < data_length) { + CRASHPAD_RAW_LOG("ScopedVMRead data_length overflow"); + return false; + } kern_return_t kr = vm_read(mach_task_self(), page_region_address, page_region_size, diff --git a/util/ios/scoped_vm_read_test.cc b/util/ios/scoped_vm_read_test.cc index 80edf04256..072d401069 100644 --- a/util/ios/scoped_vm_read_test.cc +++ b/util/ios/scoped_vm_read_test.cc @@ -30,6 +30,7 @@ TEST(ScopedVMReadTest, BasicFunctionality) { ASSERT_FALSE(vmread_bad.Read(reinterpret_cast(0x1000), 100)); vm_address_t address = 1; ASSERT_FALSE(vmread_bad.Read(&address, 1000000000)); + ASSERT_FALSE(vmread_bad.Read(&address, -1)); // array constexpr char read_me[] = "read me"; From d81d0deefcb1abee0074ebcbd3e98650704c4593 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 2 Aug 2022 19:43:00 +0200 Subject: [PATCH 212/478] Expose enabled-flag for WER --- CMakeLists.txt | 9 +++++++++ handler/CMakeLists.txt | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6e2e6d5ac..ffdc9bb1f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,15 @@ if(MSVC) $<$:/wd4577> # 'noexcept' used with no exception handling mode specified. $<$:/wd4996> # 'X' was declared deprecated. ) + + # WER support is only available starting from Win10 build 10941 + if(${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} VERSION_LESS 10.0.19041) + message(STATUS "WER support disabled. Needs target platform >= 10.0.19041 (actual: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})") + else() + SET(CRASHPAD_WER_ENABLED TRUE) + SET(CRASHPAD_WER_ENABLED TRUE PARENT_SCOPE) + message(STATUS "WER support enabled") + endif() elseif(MINGW) # redirect to wmain # FIXME: cmake 3.13 added target_link_options diff --git a/handler/CMakeLists.txt b/handler/CMakeLists.txt index fde7d26f64..8fe882ac89 100644 --- a/handler/CMakeLists.txt +++ b/handler/CMakeLists.txt @@ -123,7 +123,7 @@ if(NOT IOS) ) endif() -if(WIN32) +if(CRASHPAD_WER_ENABLED) add_library(crashpad_wer SHARED win/wer/crashpad_wer.cc win/wer/crashpad_wer.h From 6c6c2ae5638e3131a94b40b597a8f01c72336195 Mon Sep 17 00:00:00 2001 From: Alex Pankhurst Date: Mon, 8 Aug 2022 10:45:04 -0700 Subject: [PATCH 213/478] [fuchsia] migrate test to CFv2 Fuchsia is undergoing a change to how programs are run and the Crashpad tests must be migrated to the new system. Bug: fuchsia:102371 TESTED=`fx test crashpad-test` (540 passing, 1 skipped) Change-Id: I4daf7d160045b28b876a5f1aa93b0bd596461e0d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3817783 Commit-Queue: Alex Pankhurst Reviewed-by: Joshua Peraza --- BUILD.gn | 6 +-- test/fuchsia_crashpad_tests.cml | 83 +++++++++++++++++++++++++++++++++ test/fuchsia_crashpad_tests.cmx | 27 ----------- 3 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 test/fuchsia_crashpad_tests.cml delete mode 100644 test/fuchsia_crashpad_tests.cmx diff --git a/BUILD.gn b/BUILD.gn index 61546be124..c782b9b9cc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -67,7 +67,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { if (crashpad_is_in_fuchsia) { import("//build/components.gni") fuchsia_test_component("crashpad-test-component") { - manifest = "test/fuchsia_crashpad_tests.cmx" + manifest = "test/fuchsia_crashpad_tests.cml" deps = [ ":crashpad-test-resources", ":crashpad_tests", @@ -84,8 +84,8 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test_components = [ ":crashpad-test-component" ] deps = [ - "//src/connectivity/network/dns:component-legacy", - "//src/connectivity/network/netstack:component-legacy", + "//src/connectivity/network/dns:component", + "//src/connectivity/network/netstack:component", ] test_specs = { diff --git a/test/fuchsia_crashpad_tests.cml b/test/fuchsia_crashpad_tests.cml new file mode 100644 index 0000000000..b5c0c8a005 --- /dev/null +++ b/test/fuchsia_crashpad_tests.cml @@ -0,0 +1,83 @@ +// Copyright 2022 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +{ + include: [ + "//src/sys/test_runners/elf/ambient_exec.shard.cml", + "syslog/client.shard.cml", + ], + program: { + binary: "bin/crashpad_tests", + + // For ProcessSnapshotFuchsiaTest.AddressSpaceMapping. + job_policy_ambient_mark_vmo_exec: "true", + }, + children: [ + { + name: "dns_resolver", + url: "#meta/dns_resolver.cm", + }, + { + name: "netstack", + url: "#meta/netstack.cm", + }, + { + name: "crashpad_test", + url: "#meta/crashpad_test.cm", + }, + ], + use: [ + { + protocol: [ "fuchsia.net.name.Lookup" ], + from: "#dns_resolver", + }, + { + protocol: [ "fuchsia.posix.socket.Provider" ], + from: "#netstack", + }, + { + protocol: [ "fuchsia.process.Launcher" ], + }, + { + storage: "tmp", + path: "/tmp", + }, + ], + offer: [ + { + protocol: "fuchsia.logger.LogSink", + from: "parent", + to: [ + "#crashpad_test", + "#dns_resolver", + "#netstack", + ] + }, + { + protocol: "fuchsia.net.name.Lookup", + from: "#dns_resolver", + to: "#crashpad_test", + }, + { + protocol: "fuchsia.net.routes.State", + from: "#netstack", + to: "#dns_resolver", + }, + { + protocol: "fuchsia.posix.socket.Provider", + from: "#netstack", + to: "#crashpad_test", + }, + { + storage: "cache", + from: "parent", + to: [ "#netstack" ], + }, + { + storage: "tmp", + from: "parent", + to: "#crashpad_test", + rights: [ "rw*" ], + }, + ], +} diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx deleted file mode 100644 index 0a8c137f35..0000000000 --- a/test/fuchsia_crashpad_tests.cmx +++ /dev/null @@ -1,27 +0,0 @@ -{ - "facets": { - "fuchsia.test": { - "injected-services": { - "fuchsia.net.name.Lookup": "fuchsia-pkg://fuchsia.com/crashpad-test#meta/dns-resolver.cmx", - "fuchsia.posix.socket.Provider": "fuchsia-pkg://fuchsia.com/crashpad-test#meta/netstack.cmx" - } - } - }, - "include": [ - "syslog/client.shard.cmx" - ], - "program": { - "binary": "bin/crashpad_tests" - }, - "sandbox": { - "features": [ - "deprecated-ambient-replace-as-executable", - "isolated-temp" - ], - "services": [ - "fuchsia.net.name.Lookup", - "fuchsia.posix.socket.Provider", - "fuchsia.process.Launcher" - ] - } -} From 1876c6749741e5221558bfd3f9449ddba1475a2d Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Thu, 4 Aug 2022 12:53:33 -0700 Subject: [PATCH 214/478] Record memory near EIP/RIP first Checking for code-corruption is an important process in crash analysis so it is important to record code bytes first. This was already done for ARM and other processors so this change just moves EIP/RIP to the top of the list. This is important in scenarios where only a small amount of extra memory is recorded such as in the stable channel of Chrome. Bug: 1339513 Change-Id: I26367214ee66795c81000a0487987a130f2ea23a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3812374 Commit-Queue: Mark Mentovai Reviewed-by: Mark Mentovai --- snapshot/capture_memory.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index cb8231bdb9..db820add72 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -74,6 +74,7 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, Delegate* delegate) { #if defined(ARCH_CPU_X86_FAMILY) if (context.architecture == kCPUArchitectureX86_64) { + MaybeCaptureMemoryAround(delegate, context.x86_64->rip); MaybeCaptureMemoryAround(delegate, context.x86_64->rax); MaybeCaptureMemoryAround(delegate, context.x86_64->rbx); MaybeCaptureMemoryAround(delegate, context.x86_64->rcx); @@ -89,9 +90,9 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, MaybeCaptureMemoryAround(delegate, context.x86_64->r13); MaybeCaptureMemoryAround(delegate, context.x86_64->r14); MaybeCaptureMemoryAround(delegate, context.x86_64->r15); - MaybeCaptureMemoryAround(delegate, context.x86_64->rip); // Note: Shadow stack region is directly captured. } else { + MaybeCaptureMemoryAround(delegate, context.x86->eip); MaybeCaptureMemoryAround(delegate, context.x86->eax); MaybeCaptureMemoryAround(delegate, context.x86->ebx); MaybeCaptureMemoryAround(delegate, context.x86->ecx); @@ -99,7 +100,6 @@ void CaptureMemory::PointedToByContext(const CPUContext& context, MaybeCaptureMemoryAround(delegate, context.x86->edi); MaybeCaptureMemoryAround(delegate, context.x86->esi); MaybeCaptureMemoryAround(delegate, context.x86->ebp); - MaybeCaptureMemoryAround(delegate, context.x86->eip); } #elif defined(ARCH_CPU_ARM_FAMILY) if (context.architecture == kCPUArchitectureARM64) { From 0c369760bd471d57005b0a467b81ebbff2e94128 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Tue, 16 Aug 2022 17:10:57 -0400 Subject: [PATCH 215/478] Mac: update MachOImageAnnotationsReader tests for dyld4 ASAN passes locally for me with this patch in Chromium, so re-enabling it upstream as well. Bug: chromium:1334418 Change-Id: I9c9b20d7c309795cb147656374bae1229be6b418 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3833503 Reviewed-by: Mark Mentovai Commit-Queue: Leonard Grey --- .../mach_o_image_annotations_reader_test.cc | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index 74a21be670..a6062767a4 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -215,13 +215,21 @@ class TestMachOImageAnnotationsReader final case kCrashModuleInitialization: // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp // ImageLoaderMachO::doInitialization(). - expected_annotation = ModuleWithCrashyInitializer().value(); + // dyld4 no longer sets this, so instead check for fork() without + // exec() like above. + expected_annotation = + macos_version_number < 12'00'00 + ? ModuleWithCrashyInitializer().value() + : "crashed on child side of fork pre-exec"; break; case kCrashDyld: // This is independent of dyld’s error_string, which is tested - // below. - expected_annotation = "dyld: launch, loading dependent libraries"; + // below. dyld4 no longer sets this. + expected_annotation = + macos_version_number < 12'00'00 + ? "dyld: launch, loading dependent libraries" + : ""; break; default: @@ -246,22 +254,24 @@ class TestMachOImageAnnotationsReader final // dyld exposes its error_string at least as far back as Mac OS X 10.4. if (test_type_ == kCrashDyld) { - static constexpr char kExpectedAnnotation[] = - "could not load inserted library"; - size_t expected_annotation_length = strlen(kExpectedAnnotation); + std::string couldnt_load_annotation = + macos_version_number < 12'00'00 + ? "could not load inserted library" + // dyld4 no longer writes an annotation for the primary error + // See https://crbug.com/1334418/#c26 + : "tried: '/var/empty/NoDirectory/NoLibrary' (no such file)"; bool found = false; for (const std::string& annotation : all_annotations_vector) { - // Look for the expectation as a leading substring, because the actual - // string will contain the library’s pathname and, on OS X 10.9 and - // later, a reason. - if (annotation.substr(0, expected_annotation_length) == - kExpectedAnnotation) { + // Look for the expectation as a substring, because the actual + // string will contain the library’s pathname and a reason, or on + // macOS 12, only the reason. + if (annotation.find(couldnt_load_annotation) != std::string::npos) { found = true; break; } } - EXPECT_TRUE(found) << kExpectedAnnotation; + EXPECT_TRUE(found) << couldnt_load_annotation; } } @@ -460,13 +470,7 @@ TEST(MachOImageAnnotationsReader, CrashAbort) { test_mach_o_image_annotations_reader.Run(); } -#if defined(ADDRESS_SANITIZER) -// https://crbug.com/844396 -#define MAYBE_CrashModuleInitialization DISABLED_CrashModuleInitialization -#else -#define MAYBE_CrashModuleInitialization CrashModuleInitialization -#endif -TEST(MachOImageAnnotationsReader, MAYBE_CrashModuleInitialization) { +TEST(MachOImageAnnotationsReader, CrashModuleInitialization) { TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader( TestMachOImageAnnotationsReader::kCrashModuleInitialization); test_mach_o_image_annotations_reader.Run(); From 05e3bd85ebd657256c66aa4638b1f5ddc9fa4b29 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Wed, 17 Aug 2022 14:25:10 -0400 Subject: [PATCH 216/478] Mac: Expect timestamp for main executable in macOS 12+ in process reader dyld4 *does* record a timestamp for the main executable (confirmed with a test app). Bug: chromium:1268776 Change-Id: I13380181903be7b4886dfdf37f1aa42018a0ef55 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3833512 Reviewed-by: Mark Mentovai Commit-Queue: Leonard Grey --- snapshot/mac/process_reader_mac_test.cc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index aef4a7a3d5..0ee8a3bd0a 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -826,9 +826,9 @@ TEST(ProcessReaderMac, SelfModules) { FromPointerCast(_dyld_get_image_header(index))); bool expect_timestamp; - if (index == 0) { - // dyld didn’t load the main executable, so it couldn’t record its - // timestamp, and it is reported as 0. + if (index == 0 && MacOSVersionNumber() < 12'00'00) { + // Pre-dyld4, dyld didn’t set the main executable's timestamp, and it was + // reported as 0. EXPECT_EQ(modules[index].timestamp, 0); } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), modules[index].name, @@ -918,13 +918,15 @@ class ProcessReaderModulesChild final : public MachMultiprocess { EXPECT_EQ(modules[index].reader->Address(), expect_address); bool expect_timestamp; - if (index == 0 || index == modules.size() - 1) { - // dyld didn’t load the main executable or itself, so it couldn’t record - // these timestamps, and they are reported as 0. - EXPECT_EQ(modules[index].timestamp, 0); - } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), - modules[index].name, - &expect_timestamp)) { + if ((index == 0 && MacOSVersionNumber() < 12'00'00) || index == modules.size() - 1) { + // Pre-dyld4, dyld didn’t set the main executable's timestamp, and it + // was reported as 0. + // The last module is dyld. + EXPECT_EQ(modules[index].timestamp, 0); + } + else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), + modules[index].name, + &expect_timestamp)) { // cl_kernels doesn’t exist as a file, but may still have a timestamp. if (!expect_timestamp) { EXPECT_EQ(modules[index].timestamp, 0); From af96fcd576d0665a4bfcf188281bac6294c10efe Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Thu, 18 Aug 2022 14:09:51 -0400 Subject: [PATCH 217/478] Mac: use pthread_get_stack{addr,size}_np in process reader tests Currently, these tests take a pointer to a stack variable to get an address in the stack. ASAN recently enabled `detect_stack_use_after_return` by default, which breaks this approach. Bug: chromium:1319307 Change-Id: Ia828a92389cf0d45f31f9a7b999badea398f56ec Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3838735 Reviewed-by: Mark Mentovai --- snapshot/mac/process_reader_mac_test.cc | 69 ++++++++++++++++++------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 0ee8a3bd0a..9ed36357ca 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -166,7 +167,12 @@ TEST(ProcessReaderMac, SelfOneThread) { class TestThreadPool { public: struct ThreadExpectation { - mach_vm_address_t stack_address; + // The stack's base (highest) address. + mach_vm_address_t stack_base; + + // The stack's maximum size. + mach_vm_size_t stack_size; + int suspend_count; std::string thread_name; }; @@ -243,7 +249,8 @@ class TestThreadPool { CHECK_LT(thread_index, thread_infos_.size()); const auto& thread_info = thread_infos_[thread_index]; - expectation->stack_address = thread_info->stack_address; + expectation->stack_base = thread_info->stack_base; + expectation->stack_size = thread_info->stack_size; expectation->suspend_count = thread_info->suspend_count; expectation->thread_name = thread_info->thread_name; @@ -254,7 +261,8 @@ class TestThreadPool { struct ThreadInfo { ThreadInfo(const std::string& thread_name) : pthread(nullptr), - stack_address(0), + stack_base(0), + stack_size(0), ready_semaphore(0), exit_semaphore(0), suspend_count(0), @@ -265,9 +273,12 @@ class TestThreadPool { // The thread’s ID, set at the time the thread is created. pthread_t pthread; - // An address somewhere within the thread’s stack. The thread sets this in + // The base address of thread’s stack. The thread sets this in // its ThreadMain(). - mach_vm_address_t stack_address; + mach_vm_address_t stack_base; + + // The stack's maximum size. The thread sets this in its ThreadMain(). + mach_vm_size_t stack_size; // The worker thread signals ready_semaphore to indicate that it’s done // setting up its ThreadInfo structure. The main thread waits on this @@ -291,8 +302,10 @@ class TestThreadPool { ThreadInfo* thread_info = static_cast(argument); const ScopedSetThreadName scoped_set_thread_name(thread_info->thread_name); - thread_info->stack_address = - FromPointerCast(&thread_info); + pthread_t thread = pthread_self(); + thread_info->stack_base = + FromPointerCast(pthread_get_stackaddr_np(thread)); + thread_info->stack_size = pthread_get_stacksize_np(thread); thread_info->ready_semaphore.Signal(); thread_info->exit_semaphore.Wait(); @@ -343,8 +356,15 @@ void ExpectSeveralThreads(ThreadMap* thread_map, } if (iterator != thread_map->end()) { - EXPECT_GE(iterator->second.stack_address, thread.stack_region_address); - EXPECT_LT(iterator->second.stack_address, thread_stack_region_end); + mach_vm_address_t expected_stack_region_end = iterator->second.stack_base; + if (thread_index > 0) { + // Non-main threads use the stack region to store thread data. See + // _pthread_allocate. + expected_stack_region_end += sizeof(_opaque_pthread_t); + } + EXPECT_LT(iterator->second.stack_base - iterator->second.stack_size, + thread.stack_region_address); + EXPECT_EQ(expected_stack_region_end, thread_stack_region_end); EXPECT_EQ(thread.suspend_count, iterator->second.suspend_count); EXPECT_EQ(thread.name, iterator->second.thread_name); @@ -403,7 +423,10 @@ TEST(ProcessReaderMac, SelfSeveralThreads) { ThreadMap thread_map; const uint64_t self_thread_id = PthreadToThreadID(pthread_self()); TestThreadPool::ThreadExpectation expectation; - expectation.stack_address = FromPointerCast(&thread_map); + pthread_t thread = pthread_self(); + expectation.stack_base = + FromPointerCast(pthread_get_stackaddr_np(thread)); + expectation.stack_size = pthread_get_stacksize_np(thread); expectation.suspend_count = 0; thread_map[self_thread_id] = expectation; for (size_t thread_index = 0; thread_index < kChildThreads; ++thread_index) { @@ -482,9 +505,10 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedReadFileExactly(read_handle, &thread_id, sizeof(thread_id)); TestThreadPool::ThreadExpectation expectation; - CheckedReadFileExactly(read_handle, - &expectation.stack_address, - sizeof(expectation.stack_address)); + CheckedReadFileExactly( + read_handle, &expectation.stack_base, sizeof(expectation.stack_base)); + CheckedReadFileExactly( + read_handle, &expectation.stack_size, sizeof(expectation.stack_size)); CheckedReadFileExactly(read_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); @@ -529,12 +553,16 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedWriteFile(write_handle, &thread_id, sizeof(thread_id)); TestThreadPool::ThreadExpectation expectation; - expectation.stack_address = FromPointerCast(&thread_id); + pthread_t thread = pthread_self(); + expectation.stack_base = + FromPointerCast(pthread_get_stackaddr_np(thread)); + expectation.stack_size = pthread_get_stacksize_np(thread); expectation.suspend_count = 0; - CheckedWriteFile(write_handle, - &expectation.stack_address, - sizeof(expectation.stack_address)); + CheckedWriteFile( + write_handle, &expectation.stack_base, sizeof(expectation.stack_base)); + CheckedWriteFile( + write_handle, &expectation.stack_size, sizeof(expectation.stack_size)); CheckedWriteFile(write_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); @@ -553,8 +581,11 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { CheckedWriteFile(write_handle, &thread_id, sizeof(thread_id)); CheckedWriteFile(write_handle, - &expectation.stack_address, - sizeof(expectation.stack_address)); + &expectation.stack_base, + sizeof(expectation.stack_base)); + CheckedWriteFile(write_handle, + &expectation.stack_size, + sizeof(expectation.stack_size)); CheckedWriteFile(write_handle, &expectation.suspend_count, sizeof(expectation.suspend_count)); From 1d4447645d30385aeca0b5a0b52a7a70e4df7df9 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Thu, 18 Aug 2022 16:38:57 -0400 Subject: [PATCH 218/478] Mac: Fix shadow warning This caused a warning with `-Wshadow` on due to the loop below. Bug: None Change-Id: I63c4252d7ff66c416d8f0edde868a9b0a6aeb65e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3838745 Reviewed-by: Mark Mentovai Commit-Queue: Leonard Grey --- snapshot/mac/process_reader_mac_test.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 9ed36357ca..db982f9339 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -423,10 +423,9 @@ TEST(ProcessReaderMac, SelfSeveralThreads) { ThreadMap thread_map; const uint64_t self_thread_id = PthreadToThreadID(pthread_self()); TestThreadPool::ThreadExpectation expectation; - pthread_t thread = pthread_self(); - expectation.stack_base = - FromPointerCast(pthread_get_stackaddr_np(thread)); - expectation.stack_size = pthread_get_stacksize_np(thread); + expectation.stack_base = FromPointerCast( + pthread_get_stackaddr_np(pthread_self())); + expectation.stack_size = pthread_get_stacksize_np(pthread_self()); expectation.suspend_count = 0; thread_map[self_thread_id] = expectation; for (size_t thread_index = 0; thread_index < kChildThreads; ++thread_index) { From 3e80b95054c868241ee3ec291603f5babda685e1 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Thu, 18 Aug 2022 17:51:05 -0400 Subject: [PATCH 219/478] Run clang-format on process_reader_mac_test Missed this in https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3833512 Bug: None Change-Id: I90a122f3b671999464e6a62e1df7d654573d9f05 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3840479 Reviewed-by: Mark Mentovai --- snapshot/mac/process_reader_mac_test.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index db982f9339..7921311a52 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -948,15 +948,15 @@ class ProcessReaderModulesChild final : public MachMultiprocess { EXPECT_EQ(modules[index].reader->Address(), expect_address); bool expect_timestamp; - if ((index == 0 && MacOSVersionNumber() < 12'00'00) || index == modules.size() - 1) { - // Pre-dyld4, dyld didn’t set the main executable's timestamp, and it - // was reported as 0. - // The last module is dyld. - EXPECT_EQ(modules[index].timestamp, 0); - } - else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), - modules[index].name, - &expect_timestamp)) { + if ((index == 0 && MacOSVersionNumber() < 12'00'00) || + index == modules.size() - 1) { + // Pre-dyld4, dyld didn’t set the main executable's timestamp, and it + // was reported as 0. + // The last module is dyld. + EXPECT_EQ(modules[index].timestamp, 0); + } else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(), + modules[index].name, + &expect_timestamp)) { // cl_kernels doesn’t exist as a file, but may still have a timestamp. if (!expect_timestamp) { EXPECT_EQ(modules[index].timestamp, 0); From 43ea32b6fe0fe87f25ae52c71d31d4ea757a2e75 Mon Sep 17 00:00:00 2001 From: Francois Rousseau Date: Thu, 18 Aug 2022 18:10:56 -0700 Subject: [PATCH 220/478] [fuchsia] remove dependency on libcurl * crashpad_http_transport_impl is "socket" when targeting Fuchsia so the dependency on //third_party/curl:libcurl isn't actually ever added - we might as well remove it to prevent confusion Bug: fuchsia:107235 TESTED=`fx build` in Fuchsia checkout Change-Id: I75da6e7505f8ab09f9978472e93c48600f4c35cb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3840964 Commit-Queue: Francois Rousseau Reviewed-by: Joshua Peraza --- util/BUILD.gn | 4 ---- 1 file changed, 4 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 8a0a89062a..22f8e2ddcd 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -671,10 +671,6 @@ crashpad_static_library("net") { } } else if (crashpad_http_transport_impl == "libcurl") { sources += [ "net/http_transport_libcurl.cc" ] - if (crashpad_is_in_fuchsia) { - # Host Linux builds in Fuchsia don't have libcurl in a sysroot. - deps += [ "//third_party/curl:libcurl" ] - } } } From a2d0cefe018b9c33ce9ac4305e4aae610d63ed68 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Fri, 19 Aug 2022 15:54:28 -0400 Subject: [PATCH 221/478] Mac: account for PTHREAD_T_OFFSET in arm64 tests Bug: chromium:1319307 Change-Id: I3d462b7f143b63eb3173eb7245a6c0df4f75e778 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3842365 Reviewed-by: Mark Mentovai Commit-Queue: Leonard Grey --- snapshot/mac/process_reader_mac_test.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 7921311a52..93527cfb59 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -359,8 +359,15 @@ void ExpectSeveralThreads(ThreadMap* thread_map, mach_vm_address_t expected_stack_region_end = iterator->second.stack_base; if (thread_index > 0) { // Non-main threads use the stack region to store thread data. See - // _pthread_allocate. + // macOS 12 libpthread-486.100.11 src/pthread.c _pthread_allocate(). +#if defined(ARCH_CPU_ARM64) + // arm64 has an additional offset for alignment. See macOS 12 + // libpthread-486.100.11 src/pthread.c _pthread_allocate() and + // PTHREAD_T_OFFSET (defined in src/types_internal.h). + expected_stack_region_end += sizeof(_opaque_pthread_t) + 0x3000; +#else expected_stack_region_end += sizeof(_opaque_pthread_t); +#endif } EXPECT_LT(iterator->second.stack_base - iterator->second.stack_size, thread.stack_region_address); From fc2e7c06b88b801d2ccfa84bcca20ab5c31ccacb Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Mon, 22 Aug 2022 19:34:08 -0400 Subject: [PATCH 222/478] Upgrade LUCI configs to use Mac-12 Fixed: 1353832, 1355592 Change-Id: I677983b8414398fbb27f02f75fad25ff9ad8388b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3848799 Reviewed-by: Mark Mentovai Commit-Queue: Justin Cohen --- infra/config/generated/cr-buildbucket.cfg | 24 +++++++++++------------ infra/config/generated/project.cfg | 2 +- infra/config/main.star | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index a79e5cfa44..a22e2411d9 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg @@ -156,7 +156,7 @@ buckets { name: "crashpad_ios_arm64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -193,7 +193,7 @@ buckets { name: "crashpad_ios_arm64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -230,7 +230,7 @@ buckets { name: "crashpad_ios_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -266,7 +266,7 @@ buckets { name: "crashpad_ios_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -368,7 +368,7 @@ buckets { name: "crashpad_mac_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -404,7 +404,7 @@ buckets { name: "crashpad_mac_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.ci" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -658,7 +658,7 @@ buckets { name: "crashpad_ios_arm64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -692,7 +692,7 @@ buckets { name: "crashpad_ios_arm64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -726,7 +726,7 @@ buckets { name: "crashpad_ios_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -759,7 +759,7 @@ buckets { name: "crashpad_ios_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -852,7 +852,7 @@ buckets { name: "crashpad_mac_x64_dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" @@ -885,7 +885,7 @@ buckets { name: "crashpad_mac_x64_rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac-11" + dimensions: "os:Mac-12" dimensions: "pool:luci.flex.try" exe { cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" diff --git a/infra/config/generated/project.cfg b/infra/config/generated/project.cfg index 28e9f2e62e..d40ae0db55 100644 --- a/infra/config/generated/project.cfg +++ b/infra/config/generated/project.cfg @@ -7,7 +7,7 @@ name: "crashpad" access: "group:all" lucicfg { - version: "1.30.9" + version: "1.32.1" package_dir: ".." config_dir: "generated" entry_point: "main.star" diff --git a/infra/config/main.star b/infra/config/main.star index fade252303..90b07b1580 100755 --- a/infra/config/main.star +++ b/infra/config/main.star @@ -158,11 +158,11 @@ def crashpad_dimensions(platform, bucket): if platform == "fuchsia": dimensions["os"] = "Ubuntu-18.04" elif platform == "ios": - dimensions["os"] = "Mac-11" + dimensions["os"] = "Mac-12" elif platform == "linux": dimensions["os"] = "Ubuntu-18.04" elif platform == "mac": - dimensions["os"] = "Mac-11" + dimensions["os"] = "Mac-12" elif platform == "win": dimensions["os"] = "Windows-10" From 54da37c2d2c1d847530b485beaaba46f1a1bd20b Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Tue, 30 Aug 2022 16:27:51 -0400 Subject: [PATCH 223/478] Remove std::vector from crashpad_wer When assertions were enabled in Chrome in https://crrev.com/c/3833545, crashpad_wer now requires libc++ to be explicitly included if compiled with -std=c++20 because would now reference symbols defined outside the libc++ headers. We attempted to add libc++ as a dependency in https://crrev.com/c/3862974; however, that was deemed unacceptable because the library needs to be kept small in order for Windows to load it to handle crashes. Therefore, the only alternative is to update the library to remove std::vector Bug: chromium:1357827 Change-Id: I1494204a7bd679fa1632a0f08597cb7e93267196 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3864248 Reviewed-by: Joshua Peraza Commit-Queue: Alan Zhao --- handler/win/wer/crashpad_wer.cc | 25 ++++++++++++++++--------- handler/win/wer/crashpad_wer.h | 13 +++++++------ handler/win/wer/crashpad_wer_main.cc | 9 ++++++--- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/handler/win/wer/crashpad_wer.cc b/handler/win/wer/crashpad_wer.cc index f3de028e0e..6266fab6ce 100644 --- a/handler/win/wer/crashpad_wer.cc +++ b/handler/win/wer/crashpad_wer.cc @@ -61,7 +61,8 @@ ScopedHandle DuplicateFromTarget(HANDLE target_process, HANDLE target_handle) { return ScopedHandle(hTmp); } -bool ProcessException(std::vector& handled_exceptions, +bool ProcessException(DWORD* handled_exceptions, + size_t num_handled_exceptions, const PVOID pContext, const PWER_RUNTIME_EXCEPTION_INFORMATION e_info) { // Need to have been given a context. @@ -72,13 +73,15 @@ bool ProcessException(std::vector& handled_exceptions, return false; // Only deal with exceptions that crashpad would not have handled. - if (handled_exceptions.size() && - std::find(handled_exceptions.begin(), - handled_exceptions.end(), - e_info->exceptionRecord.ExceptionCode) == - handled_exceptions.end()) { - return false; + bool found = false; + for (size_t i = 0; i < num_handled_exceptions; i++) { + if (handled_exceptions[i] == e_info->exceptionRecord.ExceptionCode) { + found = true; + break; + } } + if (!found) + return false; // Grab out the handles to the crashpad server. WerRegistration target_registration = {}; @@ -168,10 +171,14 @@ bool ProcessException(std::vector& handled_exceptions, } // namespace bool ExceptionEvent( - std::vector& handled_exceptions, + DWORD* handled_exceptions, + size_t num_handled_exceptions, const PVOID pContext, const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation) { - return ProcessException(handled_exceptions, pContext, pExceptionInformation); + return ProcessException(handled_exceptions, + num_handled_exceptions, + pContext, + pExceptionInformation); } } // namespace crashpad::wer diff --git a/handler/win/wer/crashpad_wer.h b/handler/win/wer/crashpad_wer.h index 5a3a52f901..1e8202071b 100644 --- a/handler/win/wer/crashpad_wer.h +++ b/handler/win/wer/crashpad_wer.h @@ -15,8 +15,6 @@ #ifndef CRASHPAD_HANDLER_WIN_WER_CRASHPAD_WER_H_ #define CRASHPAD_HANDLER_WIN_WER_CRASHPAD_WER_H_ -#include - #include #include @@ -26,9 +24,11 @@ namespace crashpad::wer { //! In the embedder's WER runtime exception helper, call this during //! OutOfProcessExceptionEventCallback(). //! -//! \param[in] handled_exceptions is a list of exception codes that the helper -//! should pass on to crashpad handler (if possible). Provide an empty list -//! to pass every exception on to the crashpad handler. +//! \param[in] handled_exceptions is an array of exception codes that the helper +//! should pass on to crashpad handler (if possible). Provide an empty +//! array to pass every exception on to the crashpad handler. +//! \param[in] num_handled_exceptions is the number of elements in the array +//! passed to handled_exceptions. //! \param[in] pContext is the context provided by WerFault to the helper. //! \param[in] pExceptionInformation is the exception information provided by //! WerFault to the helper DLL. @@ -36,7 +36,8 @@ namespace crashpad::wer { //! \return `true` if the target process was dumped by the crashpad handler then //! terminated, or `false` otherwise. bool ExceptionEvent( - std::vector& handled_exceptions, + DWORD* handled_exceptions, + size_t num_handled_exceptions, const PVOID pContext, const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation); diff --git a/handler/win/wer/crashpad_wer_main.cc b/handler/win/wer/crashpad_wer_main.cc index 4613b35353..d33e31ebef 100644 --- a/handler/win/wer/crashpad_wer_main.cc +++ b/handler/win/wer/crashpad_wer_main.cc @@ -36,14 +36,17 @@ HRESULT OutOfProcessExceptionEventCallback( PWSTR pwszEventName, PDWORD pchSize, PDWORD pdwSignatureCount) { - std::vector wanted_exceptions = { + DWORD wanted_exceptions[] = { 0xC0000602, // STATUS_FAIL_FAST_EXCEPTION 0xC0000409, // STATUS_STACK_BUFFER_OVERRUN }; // Default to not-claiming as bailing out is easier. *pbOwnershipClaimed = FALSE; - bool result = crashpad::wer::ExceptionEvent( - wanted_exceptions, pContext, pExceptionInformation); + bool result = + crashpad::wer::ExceptionEvent(wanted_exceptions, + sizeof(wanted_exceptions) / sizeof(DWORD), + pContext, + pExceptionInformation); if (result) { *pbOwnershipClaimed = TRUE; From 261679b3d2f3336d8531ed38e110254c3e2d1c10 Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Wed, 31 Aug 2022 13:51:18 -0400 Subject: [PATCH 224/478] Move registration_protocol_win structs to their own header file registration_protocol_win.h includes , which adds an unacceptable dependency on libc++ in //components/crash/win:chrome_wer in Chrome as that file is included in crashpad_wer.cc. Rather than remove , which would require doing a lot of transitive refactoring work in Crashpad, we just extract the data structures into another file, as crashpad_wer.cc only includes registration_protocol_win.h for its struct definitions. Bug: chromium:1357827 Change-Id: Ic20c2952be07ea75d063702cd346cdca0ab65038 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3864251 Commit-Queue: Alan Zhao Reviewed-by: Joshua Peraza --- handler/win/wer/crashpad_wer.cc | 2 +- util/BUILD.gn | 3 +- util/win/registration_protocol_win.h | 143 +--------------- util/win/registration_protocol_win_structs.h | 169 +++++++++++++++++++ 4 files changed, 173 insertions(+), 144 deletions(-) create mode 100644 util/win/registration_protocol_win_structs.h diff --git a/handler/win/wer/crashpad_wer.cc b/handler/win/wer/crashpad_wer.cc index 6266fab6ce..071bb92f27 100644 --- a/handler/win/wer/crashpad_wer.cc +++ b/handler/win/wer/crashpad_wer.cc @@ -18,7 +18,7 @@ #include "handler/win/wer/crashpad_wer.h" #include "util/misc/address_types.h" -#include "util/win/registration_protocol_win.h" +#include "util/win/registration_protocol_win_structs.h" #include #include diff --git a/util/BUILD.gn b/util/BUILD.gn index 22f8e2ddcd..59e02d23b3 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -165,7 +165,7 @@ if (crashpad_is_win) { sources = [ "misc/address_types.h", "win/address_types.h", - "win/registration_protocol_win.h", + "win/registration_protocol_win_structs.h", ] public_deps = [ "../third_party/mini_chromium:build" ] public_configs = [ "..:crashpad_config" ] @@ -505,6 +505,7 @@ crashpad_static_library("util") { "win/process_structs.h", "win/registration_protocol_win.cc", "win/registration_protocol_win.h", + "win/registration_protocol_win_structs.h", "win/safe_terminate_process.h", "win/scoped_handle.cc", "win/scoped_handle.h", diff --git a/util/win/registration_protocol_win.h b/util/win/registration_protocol_win.h index e467fd84a2..de3d57a4c2 100644 --- a/util/win/registration_protocol_win.h +++ b/util/win/registration_protocol_win.h @@ -21,151 +21,10 @@ #include #include "util/win/address_types.h" +#include "util/win/registration_protocol_win_structs.h" namespace crashpad { -#pragma pack(push, 1) - -//! \brief Structure read out of the client process by the crash handler when an -//! exception occurs. -struct ExceptionInformation { - //! \brief The address of an EXCEPTION_POINTERS structure in the client - //! process that describes the exception. - WinVMAddress exception_pointers; - - //! \brief The thread on which the exception happened. - DWORD thread_id; -}; - -//! \brief Context to be passed to WerRegisterRuntimeExceptionModule(). -//! -//! Used by the crashpad client, and the WER exception DLL. -struct WerRegistration { - //! \brief The expected value of `version`. This should be changed whenever - //! this struct is modified incompatibly. - enum { kWerRegistrationVersion = 1 }; - //! \brief Version field to detect skew between target process and helper. - //! Should be set to kWerRegistrationVersion. - int version; - //! \brief Used by DumpWithoutCrashing and the WER module to initiate a dump. - //! These handles are leaked in the client process. - HANDLE dump_without_crashing; - //! \brief Used by DumpWithoutCrashing to signal that a dump has been taken. - //! These handles are leaked in the client process. - HANDLE dump_completed; - //! \brief Set just before and cleared just after the events above are - //! triggered or signalled in a normal DumpWithoutCrashing call. - //! When `true` the WER handler should not set the exception structures until - //! after dump_completed has been signalled. - bool in_dump_without_crashing; - //! \brief Address of g_non_crash_exception_information. - //! - //! Provided by the target process. Just before dumping we will point - //! (*crashpad_exception_info).exception_pointers at `pointers`. As WerFault - //! loads the helper with the same bitness as the client this can be void*. - void* crashpad_exception_info; - //! \brief These will point into the `exception` and `context` members in this - //! structure. - //! - //! Filled in by the helper DLL. - EXCEPTION_POINTERS pointers; - //! \brief The exception provided by WerFault. - //! - //! Filled in by the helper DLL. - EXCEPTION_RECORD exception; - //! \brief The context provided by WerFault. - //! - //! Filled in by the helper DLL. - CONTEXT context; -}; - -//! \brief A client registration request. -struct RegistrationRequest { - //! \brief The expected value of `version`. This should be changed whenever - //! the messages or ExceptionInformation are modified incompatibly. - enum { kMessageVersion = 1 }; - - //! \brief Version field to detect skew between client and server. Should be - //! set to kMessageVersion. - int version; - - //! \brief The PID of the client process. - DWORD client_process_id; - - //! \brief The address, in the client process's address space, of an - //! ExceptionInformation structure, used when handling a crash dump - //! request. - WinVMAddress crash_exception_information; - - //! \brief The address, in the client process's address space, of an - //! ExceptionInformation structure, used when handling a non-crashing dump - //! request. - WinVMAddress non_crash_exception_information; - - //! \brief The address, in the client process's address space, of a - //! `CRITICAL_SECTION` allocated with a valid .DebugInfo field. This can - //! be accomplished by using - //! InitializeCriticalSectionWithDebugInfoIfPossible() or equivalent. This - //! value can be `0`, however then limited lock data will be available in - //! minidumps. - WinVMAddress critical_section_address; -}; - -//! \brief A message only sent to the server by itself to trigger shutdown. -struct ShutdownRequest { - //! \brief A randomly generated token used to validate the the shutdown - //! request was not sent from another process. - uint64_t token; -}; - -//! \brief The message passed from client to server by -//! SendToCrashHandlerServer(). -struct ClientToServerMessage { - //! \brief Indicates which field of the union is in use. - enum Type : uint32_t { - //! \brief For RegistrationRequest. - kRegister, - - //! \brief For ShutdownRequest. - kShutdown, - - //! \brief An empty message sent by the initial client in asynchronous mode. - //! No data is required, this just confirms that the server is ready to - //! accept client registrations. - kPing, - } type; - - union { - RegistrationRequest registration; - ShutdownRequest shutdown; - }; -}; - -//! \brief A client registration response. -struct RegistrationResponse { - //! \brief An event `HANDLE`, valid in the client process, that should be - //! signaled to request a crash report. Clients should convert the value - //! to a `HANDLE` by calling IntToHandle(). - int request_crash_dump_event; - - //! \brief An event `HANDLE`, valid in the client process, that should be - //! signaled to request a non-crashing dump be taken. Clients should - //! convert the value to a `HANDLE` by calling IntToHandle(). - int request_non_crash_dump_event; - - //! \brief An event `HANDLE`, valid in the client process, that will be - //! signaled by the server when the non-crashing dump is complete. Clients - //! should convert the value to a `HANDLE` by calling IntToHandle(). - int non_crash_dump_completed_event; -}; - -//! \brief The response sent back to the client via SendToCrashHandlerServer(). -union ServerToClientMessage { - RegistrationResponse registration; -}; - -#pragma pack(pop) - //! \brief Connect over the given \a pipe_name, passing \a message to the //! server, storing the server's reply into \a response. //! diff --git a/util/win/registration_protocol_win_structs.h b/util/win/registration_protocol_win_structs.h new file mode 100644 index 0000000000..2800caccb0 --- /dev/null +++ b/util/win/registration_protocol_win_structs.h @@ -0,0 +1,169 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_WIN_REGISTRATION_PROTOCOL_WIN_STRUCTS_H_ +#define CRASHPAD_UTIL_WIN_REGISTRATION_PROTOCOL_WIN_STRUCTS_H_ + +#include +#include + +#include "util/win/address_types.h" + +namespace crashpad { + +#pragma pack(push, 1) + +//! \brief Structure read out of the client process by the crash handler when an +//! exception occurs. +struct ExceptionInformation { + //! \brief The address of an EXCEPTION_POINTERS structure in the client + //! process that describes the exception. + WinVMAddress exception_pointers; + + //! \brief The thread on which the exception happened. + DWORD thread_id; +}; + +//! \brief Context to be passed to WerRegisterRuntimeExceptionModule(). +//! +//! Used by the crashpad client, and the WER exception DLL. +struct WerRegistration { + //! \brief The expected value of `version`. This should be changed whenever + //! this struct is modified incompatibly. + enum { kWerRegistrationVersion = 1 }; + //! \brief Version field to detect skew between target process and helper. + //! Should be set to kWerRegistrationVersion. + int version; + //! \brief Used by DumpWithoutCrashing and the WER module to initiate a dump. + //! These handles are leaked in the client process. + HANDLE dump_without_crashing; + //! \brief Used by DumpWithoutCrashing to signal that a dump has been taken. + //! These handles are leaked in the client process. + HANDLE dump_completed; + //! \brief Set just before and cleared just after the events above are + //! triggered or signalled in a normal DumpWithoutCrashing call. + //! When `true` the WER handler should not set the exception structures until + //! after dump_completed has been signalled. + bool in_dump_without_crashing; + //! \brief Address of g_non_crash_exception_information. + //! + //! Provided by the target process. Just before dumping we will point + //! (*crashpad_exception_info).exception_pointers at `pointers`. As WerFault + //! loads the helper with the same bitness as the client this can be void*. + void* crashpad_exception_info; + //! \brief These will point into the `exception` and `context` members in this + //! structure. + //! + //! Filled in by the helper DLL. + EXCEPTION_POINTERS pointers; + //! \brief The exception provided by WerFault. + //! + //! Filled in by the helper DLL. + EXCEPTION_RECORD exception; + //! \brief The context provided by WerFault. + //! + //! Filled in by the helper DLL. + CONTEXT context; +}; + +//! \brief A client registration request. +struct RegistrationRequest { + //! \brief The expected value of `version`. This should be changed whenever + //! the messages or ExceptionInformation are modified incompatibly. + enum { kMessageVersion = 1 }; + + //! \brief Version field to detect skew between client and server. Should be + //! set to kMessageVersion. + int version; + + //! \brief The PID of the client process. + DWORD client_process_id; + + //! \brief The address, in the client process's address space, of an + //! ExceptionInformation structure, used when handling a crash dump + //! request. + WinVMAddress crash_exception_information; + + //! \brief The address, in the client process's address space, of an + //! ExceptionInformation structure, used when handling a non-crashing dump + //! request. + WinVMAddress non_crash_exception_information; + + //! \brief The address, in the client process's address space, of a + //! `CRITICAL_SECTION` allocated with a valid .DebugInfo field. This can + //! be accomplished by using + //! InitializeCriticalSectionWithDebugInfoIfPossible() or equivalent. This + //! value can be `0`, however then limited lock data will be available in + //! minidumps. + WinVMAddress critical_section_address; +}; + +//! \brief A message only sent to the server by itself to trigger shutdown. +struct ShutdownRequest { + //! \brief A randomly generated token used to validate the the shutdown + //! request was not sent from another process. + uint64_t token; +}; + +//! \brief The message passed from client to server by +//! SendToCrashHandlerServer(). +struct ClientToServerMessage { + //! \brief Indicates which field of the union is in use. + enum Type : uint32_t { + //! \brief For RegistrationRequest. + kRegister, + + //! \brief For ShutdownRequest. + kShutdown, + + //! \brief An empty message sent by the initial client in asynchronous mode. + //! No data is required, this just confirms that the server is ready to + //! accept client registrations. + kPing, + } type; + + union { + RegistrationRequest registration; + ShutdownRequest shutdown; + }; +}; + +//! \brief A client registration response. +struct RegistrationResponse { + //! \brief An event `HANDLE`, valid in the client process, that should be + //! signaled to request a crash report. Clients should convert the value + //! to a `HANDLE` by calling IntToHandle(). + int request_crash_dump_event; + + //! \brief An event `HANDLE`, valid in the client process, that should be + //! signaled to request a non-crashing dump be taken. Clients should + //! convert the value to a `HANDLE` by calling IntToHandle(). + int request_non_crash_dump_event; + + //! \brief An event `HANDLE`, valid in the client process, that will be + //! signaled by the server when the non-crashing dump is complete. Clients + //! should convert the value to a `HANDLE` by calling IntToHandle(). + int non_crash_dump_completed_event; +}; + +//! \brief The response sent back to the client via SendToCrashHandlerServer(). +union ServerToClientMessage { + RegistrationResponse registration; +}; + +#pragma pack(pop) + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_REGISTRATION_PROTOCOL_WIN_STRUCTS_H_ From 6278690abe6ef0dda047e67dc1d0c49ce7af3811 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 6 Sep 2022 19:14:07 -0400 Subject: [PATCH 225/478] Update copyright boilerplate, 2022 edition (Crashpad) sed -i '' -E -e 's/Copyright (.+) The Crashpad Authors\. All rights reserved\.$/Copyright \1 The Crashpad Authors/' $(git grep -El 'Copyright (.+) The Crashpad Authors\. All rights reserved\.$') Bug: chromium:1098010 Change-Id: I8d6138469ddbe3d281a5d83f64cf918ec2491611 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3878262 Reviewed-by: Joshua Peraza Commit-Queue: Mark Mentovai --- .clang-format | 2 +- .gitattributes | 2 +- .gitignore | 2 +- .gn | 2 +- .style.yapf | 2 +- .vpython | 2 +- .vpython3 | 2 +- BUILD.gn | 2 +- DEPS | 4 ++-- README.md | 2 +- build/BUILD.gn | 2 +- build/BUILDCONFIG.gn | 2 +- build/crashpad_buildconfig.gni | 2 +- build/crashpad_fuzzer_test.gni | 2 +- build/install_linux_sysroot.py | 2 +- build/ios/convert_gn_xcodeproj.py | 2 +- build/ios/setup_ios_gn.config | 2 +- build/ios/setup_ios_gn.py | 2 +- build/run_tests.py | 2 +- build/test.gni | 2 +- client/BUILD.gn | 2 +- client/annotation.cc | 2 +- client/annotation.h | 2 +- client/annotation_list.cc | 2 +- client/annotation_list.h | 2 +- client/annotation_list_test.cc | 2 +- client/annotation_test.cc | 2 +- client/client_argv_handling.cc | 2 +- client/client_argv_handling.h | 2 +- client/crash_report_database.cc | 2 +- client/crash_report_database.h | 2 +- client/crash_report_database_generic.cc | 2 +- client/crash_report_database_mac.mm | 2 +- client/crash_report_database_test.cc | 2 +- client/crash_report_database_win.cc | 2 +- client/crashpad_client.h | 2 +- client/crashpad_client_fuchsia.cc | 2 +- client/crashpad_client_ios.cc | 2 +- client/crashpad_client_ios_test.mm | 2 +- client/crashpad_client_linux.cc | 2 +- client/crashpad_client_linux_test.cc | 2 +- client/crashpad_client_mac.cc | 2 +- client/crashpad_client_win.cc | 2 +- client/crashpad_client_win_test.cc | 2 +- client/crashpad_info.cc | 2 +- client/crashpad_info.h | 2 +- client/crashpad_info_note.S | 2 +- client/ios_handler/exception_processor.h | 2 +- client/ios_handler/exception_processor.mm | 2 +- client/ios_handler/exception_processor_test.mm | 2 +- client/ios_handler/in_process_handler.cc | 2 +- client/ios_handler/in_process_handler.h | 2 +- client/ios_handler/in_process_handler_test.cc | 2 +- client/ios_handler/in_process_intermediate_dump_handler.cc | 2 +- client/ios_handler/in_process_intermediate_dump_handler.h | 2 +- .../ios_handler/in_process_intermediate_dump_handler_test.cc | 2 +- .../prune_intermediate_dumps_and_crash_reports_thread.cc | 2 +- .../prune_intermediate_dumps_and_crash_reports_thread.h | 2 +- client/prune_crash_reports.cc | 2 +- client/prune_crash_reports.h | 2 +- client/prune_crash_reports_test.cc | 2 +- client/pthread_create_linux.cc | 2 +- client/settings.cc | 2 +- client/settings.h | 2 +- client/settings_test.cc | 2 +- client/simple_address_range_bag.h | 2 +- client/simple_address_range_bag_test.cc | 2 +- client/simple_string_dictionary.h | 2 +- client/simple_string_dictionary_test.cc | 2 +- client/simulate_crash.h | 2 +- client/simulate_crash_ios.h | 2 +- client/simulate_crash_linux.h | 2 +- client/simulate_crash_mac.cc | 2 +- client/simulate_crash_mac.h | 2 +- client/simulate_crash_mac_test.cc | 2 +- client/simulate_crash_win.h | 2 +- codereview.settings | 2 +- compat/BUILD.gn | 2 +- compat/android/dlfcn_internal.cc | 2 +- compat/android/dlfcn_internal.h | 2 +- compat/android/elf.h | 2 +- compat/android/linux/elf.h | 2 +- compat/android/linux/prctl.h | 2 +- compat/android/linux/ptrace.h | 2 +- compat/android/sched.h | 2 +- compat/android/sys/epoll.cc | 2 +- compat/android/sys/epoll.h | 2 +- compat/android/sys/mman.h | 2 +- compat/android/sys/mman_mmap.cc | 2 +- compat/android/sys/syscall.h | 2 +- compat/android/sys/user.h | 2 +- compat/ios/mach/exc.defs | 2 +- compat/ios/mach/mach_exc.defs | 2 +- compat/ios/mach/mach_types.defs | 2 +- compat/ios/mach/machine/machine_types.defs | 2 +- compat/ios/mach/std_types.defs | 2 +- compat/linux/signal.h | 2 +- compat/linux/sys/mman.h | 2 +- compat/linux/sys/mman_memfd_create.cc | 2 +- compat/linux/sys/ptrace.h | 2 +- compat/linux/sys/user.h | 2 +- compat/mac/Availability.h | 2 +- compat/mac/AvailabilityVersions.h | 2 +- compat/mac/kern/exc_resource.h | 2 +- compat/mac/mach-o/loader.h | 2 +- compat/mac/mach/i386/thread_state.h | 2 +- compat/mac/mach/mach.h | 2 +- compat/mac/sys/resource.h | 2 +- compat/non_mac/mach-o/loader.h | 2 +- compat/non_mac/mach/mach.h | 2 +- compat/non_mac/mach/machine.h | 2 +- compat/non_mac/mach/vm_prot.h | 2 +- compat/non_win/dbghelp.h | 2 +- compat/non_win/minwinbase.h | 2 +- compat/non_win/timezoneapi.h | 2 +- compat/non_win/verrsrc.h | 2 +- compat/non_win/windows.h | 2 +- compat/non_win/winnt.h | 2 +- compat/win/getopt.h | 2 +- compat/win/strings.cc | 2 +- compat/win/strings.h | 2 +- compat/win/sys/time.h | 2 +- compat/win/sys/types.h | 2 +- compat/win/time.cc | 2 +- compat/win/time.h | 2 +- compat/win/winbase.h | 2 +- compat/win/winnt.h | 2 +- compat/win/winternl.h | 2 +- doc/appengine/src/crashpad-home/app.yaml | 2 +- doc/appengine/src/crashpad-home/main.go | 2 +- doc/developing.md | 2 +- doc/ios_overview_design.md | 2 +- doc/man.md | 2 +- doc/overview_design.md | 2 +- doc/status.md | 2 +- doc/support/compat.sh | 2 +- doc/support/crashpad.doxy.h | 2 +- doc/support/crashpad_doxygen.css | 2 +- doc/support/generate.sh | 2 +- doc/support/generate_doxygen.py | 2 +- doc/support/generate_git.sh | 2 +- handler/BUILD.gn | 2 +- handler/crash_report_upload_thread.cc | 2 +- handler/crash_report_upload_thread.h | 2 +- handler/crashpad_handler.md | 2 +- handler/crashpad_handler_main.cc | 2 +- handler/crashpad_handler_test.cc | 2 +- handler/crashpad_handler_test_extended_handler.cc | 2 +- handler/handler_main.cc | 2 +- handler/handler_main.h | 2 +- handler/linux/capture_snapshot.cc | 2 +- handler/linux/capture_snapshot.h | 2 +- handler/linux/crash_report_exception_handler.cc | 2 +- handler/linux/crash_report_exception_handler.h | 2 +- handler/linux/cros_crash_report_exception_handler.cc | 2 +- handler/linux/cros_crash_report_exception_handler.h | 2 +- handler/linux/exception_handler_server.cc | 2 +- handler/linux/exception_handler_server.h | 2 +- handler/linux/exception_handler_server_test.cc | 2 +- handler/linux/handler_trampoline.cc | 2 +- handler/mac/crash_report_exception_handler.cc | 2 +- handler/mac/crash_report_exception_handler.h | 2 +- handler/mac/exception_handler_server.cc | 2 +- handler/mac/exception_handler_server.h | 2 +- handler/mac/file_limit_annotation.cc | 2 +- handler/mac/file_limit_annotation.h | 2 +- handler/main.cc | 2 +- handler/minidump_to_upload_parameters.cc | 2 +- handler/minidump_to_upload_parameters.h | 2 +- handler/minidump_to_upload_parameters_test.cc | 2 +- handler/prune_crash_reports_thread.cc | 2 +- handler/prune_crash_reports_thread.h | 2 +- handler/user_stream_data_source.cc | 2 +- handler/user_stream_data_source.h | 2 +- handler/win/.gitattributes | 2 +- handler/win/crash_other_program.cc | 2 +- handler/win/crash_report_exception_handler.cc | 2 +- handler/win/crash_report_exception_handler.h | 2 +- handler/win/crashy_signal.cc | 2 +- handler/win/crashy_test_program.cc | 2 +- handler/win/crashy_test_z7_loader.cc | 2 +- handler/win/fake_handler_that_crashes_at_startup.cc | 2 +- handler/win/fastfail_test_program.cc | 2 +- handler/win/hanging_program.cc | 2 +- handler/win/loader_lock_dll.cc | 2 +- handler/win/self_destroying_test_program.cc | 2 +- handler/win/wer/BUILD.gn | 2 +- handler/win/wer/crashpad_wer.cc | 2 +- handler/win/wer/crashpad_wer.def | 2 +- handler/win/wer/crashpad_wer.h | 2 +- handler/win/wer/crashpad_wer_main.cc | 2 +- handler/win/wer/crashpad_wer_module_unittest.cc | 2 +- handler/win/z7_test.cpp | 2 +- infra/config/PRESUBMIT.py | 2 +- infra/config/main.star | 2 +- minidump/BUILD.gn | 2 +- minidump/minidump_annotation_writer.cc | 2 +- minidump/minidump_annotation_writer.h | 2 +- minidump/minidump_annotation_writer_test.cc | 2 +- minidump/minidump_byte_array_writer.cc | 2 +- minidump/minidump_byte_array_writer.h | 2 +- minidump/minidump_byte_array_writer_test.cc | 2 +- minidump/minidump_context.h | 2 +- minidump/minidump_context_writer.cc | 2 +- minidump/minidump_context_writer.h | 2 +- minidump/minidump_context_writer_test.cc | 2 +- minidump/minidump_crashpad_info_writer.cc | 2 +- minidump/minidump_crashpad_info_writer.h | 2 +- minidump/minidump_crashpad_info_writer_test.cc | 2 +- minidump/minidump_exception_writer.cc | 2 +- minidump/minidump_exception_writer.h | 2 +- minidump/minidump_exception_writer_test.cc | 2 +- minidump/minidump_extensions.cc | 2 +- minidump/minidump_extensions.h | 2 +- minidump/minidump_file_writer.cc | 2 +- minidump/minidump_file_writer.h | 2 +- minidump/minidump_file_writer_test.cc | 2 +- minidump/minidump_handle_writer.cc | 2 +- minidump/minidump_handle_writer.h | 2 +- minidump/minidump_handle_writer_test.cc | 2 +- minidump/minidump_memory_info_writer.cc | 2 +- minidump/minidump_memory_info_writer.h | 2 +- minidump/minidump_memory_info_writer_test.cc | 2 +- minidump/minidump_memory_writer.cc | 2 +- minidump/minidump_memory_writer.h | 2 +- minidump/minidump_memory_writer_test.cc | 2 +- minidump/minidump_misc_info_writer.cc | 2 +- minidump/minidump_misc_info_writer.h | 2 +- minidump/minidump_misc_info_writer_test.cc | 2 +- minidump/minidump_module_crashpad_info_writer.cc | 2 +- minidump/minidump_module_crashpad_info_writer.h | 2 +- minidump/minidump_module_crashpad_info_writer_test.cc | 2 +- minidump/minidump_module_writer.cc | 2 +- minidump/minidump_module_writer.h | 2 +- minidump/minidump_module_writer_test.cc | 2 +- minidump/minidump_rva_list_writer.cc | 2 +- minidump/minidump_rva_list_writer.h | 2 +- minidump/minidump_rva_list_writer_test.cc | 2 +- minidump/minidump_simple_string_dictionary_writer.cc | 2 +- minidump/minidump_simple_string_dictionary_writer.h | 2 +- minidump/minidump_simple_string_dictionary_writer_test.cc | 2 +- minidump/minidump_stream_writer.cc | 2 +- minidump/minidump_stream_writer.h | 2 +- minidump/minidump_string_writer.cc | 2 +- minidump/minidump_string_writer.h | 2 +- minidump/minidump_string_writer_test.cc | 2 +- minidump/minidump_system_info_writer.cc | 2 +- minidump/minidump_system_info_writer.h | 2 +- minidump/minidump_system_info_writer_test.cc | 2 +- minidump/minidump_thread_id_map.cc | 2 +- minidump/minidump_thread_id_map.h | 2 +- minidump/minidump_thread_id_map_test.cc | 2 +- minidump/minidump_thread_name_list_writer.cc | 2 +- minidump/minidump_thread_name_list_writer.h | 2 +- minidump/minidump_thread_name_list_writer_test.cc | 2 +- minidump/minidump_thread_writer.cc | 2 +- minidump/minidump_thread_writer.h | 2 +- minidump/minidump_thread_writer_test.cc | 2 +- minidump/minidump_unloaded_module_writer.cc | 2 +- minidump/minidump_unloaded_module_writer.h | 2 +- minidump/minidump_unloaded_module_writer_test.cc | 2 +- minidump/minidump_user_extension_stream_data_source.cc | 2 +- minidump/minidump_user_extension_stream_data_source.h | 2 +- minidump/minidump_user_stream_writer.cc | 2 +- minidump/minidump_user_stream_writer.h | 2 +- minidump/minidump_user_stream_writer_test.cc | 2 +- minidump/minidump_writable.cc | 2 +- minidump/minidump_writable.h | 2 +- minidump/minidump_writable_test.cc | 2 +- minidump/minidump_writer_util.cc | 2 +- minidump/minidump_writer_util.h | 2 +- minidump/test/minidump_byte_array_writer_test_util.cc | 2 +- minidump/test/minidump_byte_array_writer_test_util.h | 2 +- minidump/test/minidump_context_test_util.cc | 2 +- minidump/test/minidump_context_test_util.h | 2 +- minidump/test/minidump_file_writer_test_util.cc | 2 +- minidump/test/minidump_file_writer_test_util.h | 2 +- minidump/test/minidump_memory_writer_test_util.cc | 2 +- minidump/test/minidump_memory_writer_test_util.h | 2 +- minidump/test/minidump_rva_list_test_util.cc | 2 +- minidump/test/minidump_rva_list_test_util.h | 2 +- minidump/test/minidump_string_writer_test_util.cc | 2 +- minidump/test/minidump_string_writer_test_util.h | 2 +- minidump/test/minidump_user_extension_stream_util.cc | 2 +- minidump/test/minidump_user_extension_stream_util.h | 2 +- minidump/test/minidump_writable_test_util.cc | 2 +- minidump/test/minidump_writable_test_util.h | 2 +- navbar.md | 2 +- package.h | 2 +- snapshot/BUILD.gn | 2 +- snapshot/annotation_snapshot.cc | 2 +- snapshot/annotation_snapshot.h | 2 +- snapshot/capture_memory.cc | 2 +- snapshot/capture_memory.h | 2 +- snapshot/cpu_architecture.h | 2 +- snapshot/cpu_context.cc | 2 +- snapshot/cpu_context.h | 2 +- snapshot/cpu_context_test.cc | 2 +- snapshot/crashpad_info_client_options.cc | 2 +- snapshot/crashpad_info_client_options.h | 2 +- snapshot/crashpad_info_client_options_test.cc | 2 +- snapshot/crashpad_info_client_options_test_module.cc | 2 +- snapshot/crashpad_info_size_test_module.cc | 2 +- snapshot/crashpad_info_size_test_note.S | 2 +- snapshot/crashpad_types/crashpad_info_reader.cc | 2 +- snapshot/crashpad_types/crashpad_info_reader.h | 2 +- snapshot/crashpad_types/crashpad_info_reader_test.cc | 2 +- snapshot/crashpad_types/image_annotation_reader.cc | 2 +- snapshot/crashpad_types/image_annotation_reader.h | 2 +- snapshot/crashpad_types/image_annotation_reader_test.cc | 2 +- snapshot/elf/elf_dynamic_array_reader.cc | 2 +- snapshot/elf/elf_dynamic_array_reader.h | 2 +- snapshot/elf/elf_image_reader.cc | 2 +- snapshot/elf/elf_image_reader.h | 2 +- snapshot/elf/elf_image_reader_fuzzer.cc | 2 +- snapshot/elf/elf_image_reader_fuzzer_corpus/.gitattributes | 2 +- snapshot/elf/elf_image_reader_test.cc | 2 +- snapshot/elf/elf_image_reader_test_note.S | 2 +- snapshot/elf/elf_symbol_table_reader.cc | 2 +- snapshot/elf/elf_symbol_table_reader.h | 2 +- snapshot/elf/module_snapshot_elf.cc | 2 +- snapshot/elf/module_snapshot_elf.h | 2 +- snapshot/elf/test_exported_symbols.sym | 2 +- snapshot/exception_snapshot.h | 2 +- snapshot/fuchsia/cpu_context_fuchsia.cc | 2 +- snapshot/fuchsia/cpu_context_fuchsia.h | 2 +- snapshot/fuchsia/exception_snapshot_fuchsia.cc | 2 +- snapshot/fuchsia/exception_snapshot_fuchsia.h | 2 +- snapshot/fuchsia/memory_map_fuchsia.cc | 2 +- snapshot/fuchsia/memory_map_fuchsia.h | 2 +- snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc | 2 +- snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h | 2 +- snapshot/fuchsia/process_reader_fuchsia.cc | 2 +- snapshot/fuchsia/process_reader_fuchsia.h | 2 +- snapshot/fuchsia/process_reader_fuchsia_test.cc | 2 +- snapshot/fuchsia/process_snapshot_fuchsia.cc | 2 +- snapshot/fuchsia/process_snapshot_fuchsia.h | 2 +- snapshot/fuchsia/process_snapshot_fuchsia_test.cc | 2 +- snapshot/fuchsia/system_snapshot_fuchsia.cc | 2 +- snapshot/fuchsia/system_snapshot_fuchsia.h | 2 +- snapshot/fuchsia/thread_snapshot_fuchsia.cc | 2 +- snapshot/fuchsia/thread_snapshot_fuchsia.h | 2 +- snapshot/handle_snapshot.cc | 2 +- snapshot/handle_snapshot.h | 2 +- snapshot/hash_types_test.cc | 2 +- snapshot/ios/exception_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/exception_snapshot_ios_intermediate_dump.h | 2 +- snapshot/ios/intermediate_dump_reader_util.cc | 2 +- snapshot/ios/intermediate_dump_reader_util.h | 2 +- snapshot/ios/memory_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/memory_snapshot_ios_intermediate_dump.h | 2 +- snapshot/ios/memory_snapshot_ios_intermediate_dump_test.cc | 2 +- snapshot/ios/module_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/module_snapshot_ios_intermediate_dump.h | 2 +- snapshot/ios/process_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/process_snapshot_ios_intermediate_dump.h | 2 +- snapshot/ios/process_snapshot_ios_intermediate_dump_test.cc | 2 +- snapshot/ios/system_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/system_snapshot_ios_intermediate_dump.h | 2 +- snapshot/ios/thread_snapshot_ios_intermediate_dump.cc | 2 +- snapshot/ios/thread_snapshot_ios_intermediate_dump.h | 2 +- snapshot/linux/capture_memory_delegate_linux.cc | 2 +- snapshot/linux/capture_memory_delegate_linux.h | 2 +- snapshot/linux/cpu_context_linux.cc | 2 +- snapshot/linux/cpu_context_linux.h | 2 +- snapshot/linux/debug_rendezvous.cc | 2 +- snapshot/linux/debug_rendezvous.h | 2 +- snapshot/linux/debug_rendezvous_test.cc | 2 +- snapshot/linux/exception_snapshot_linux.cc | 2 +- snapshot/linux/exception_snapshot_linux.h | 2 +- snapshot/linux/exception_snapshot_linux_test.cc | 2 +- snapshot/linux/process_reader_linux.cc | 2 +- snapshot/linux/process_reader_linux.h | 2 +- snapshot/linux/process_reader_linux_test.cc | 2 +- snapshot/linux/process_snapshot_linux.cc | 2 +- snapshot/linux/process_snapshot_linux.h | 2 +- snapshot/linux/signal_context.h | 2 +- snapshot/linux/system_snapshot_linux.cc | 2 +- snapshot/linux/system_snapshot_linux.h | 2 +- snapshot/linux/system_snapshot_linux_test.cc | 2 +- snapshot/linux/test_modules.cc | 2 +- snapshot/linux/test_modules.h | 2 +- snapshot/linux/thread_snapshot_linux.cc | 2 +- snapshot/linux/thread_snapshot_linux.h | 2 +- snapshot/mac/cpu_context_mac.cc | 2 +- snapshot/mac/cpu_context_mac.h | 2 +- snapshot/mac/cpu_context_mac_test.cc | 2 +- snapshot/mac/exception_snapshot_mac.cc | 2 +- snapshot/mac/exception_snapshot_mac.h | 2 +- snapshot/mac/mach_o_image_annotations_reader.cc | 2 +- snapshot/mac/mach_o_image_annotations_reader.h | 2 +- snapshot/mac/mach_o_image_annotations_reader_test.cc | 2 +- ...image_annotations_reader_test_module_crashy_initializer.cc | 2 +- snapshot/mac/mach_o_image_annotations_reader_test_no_op.cc | 2 +- snapshot/mac/mach_o_image_reader.cc | 2 +- snapshot/mac/mach_o_image_reader.h | 2 +- snapshot/mac/mach_o_image_reader_test.cc | 2 +- snapshot/mac/mach_o_image_segment_reader.cc | 2 +- snapshot/mac/mach_o_image_segment_reader.h | 2 +- snapshot/mac/mach_o_image_segment_reader_test.cc | 2 +- snapshot/mac/mach_o_image_symbol_table_reader.cc | 2 +- snapshot/mac/mach_o_image_symbol_table_reader.h | 2 +- snapshot/mac/module_snapshot_mac.cc | 2 +- snapshot/mac/module_snapshot_mac.h | 2 +- snapshot/mac/process_reader_mac.cc | 2 +- snapshot/mac/process_reader_mac.h | 2 +- snapshot/mac/process_reader_mac_test.cc | 2 +- snapshot/mac/process_snapshot_mac.cc | 2 +- snapshot/mac/process_snapshot_mac.h | 2 +- snapshot/mac/process_types.cc | 2 +- snapshot/mac/process_types.h | 2 +- snapshot/mac/process_types/all.proctype | 2 +- snapshot/mac/process_types/annotation.proctype | 2 +- snapshot/mac/process_types/crashpad_info.proctype | 2 +- snapshot/mac/process_types/crashreporterclient.proctype | 2 +- snapshot/mac/process_types/custom.cc | 2 +- snapshot/mac/process_types/dyld_images.proctype | 2 +- snapshot/mac/process_types/flavors.h | 2 +- snapshot/mac/process_types/internal.h | 2 +- snapshot/mac/process_types/loader.proctype | 2 +- snapshot/mac/process_types/nlist.proctype | 2 +- snapshot/mac/process_types/traits.h | 2 +- snapshot/mac/process_types_test.cc | 2 +- snapshot/mac/system_snapshot_mac.cc | 2 +- snapshot/mac/system_snapshot_mac.h | 2 +- snapshot/mac/system_snapshot_mac_test.cc | 2 +- snapshot/mac/thread_snapshot_mac.cc | 2 +- snapshot/mac/thread_snapshot_mac.h | 2 +- snapshot/memory_map_region_snapshot.h | 2 +- snapshot/memory_snapshot.cc | 2 +- snapshot/memory_snapshot.h | 2 +- snapshot/memory_snapshot_generic.h | 2 +- snapshot/memory_snapshot_test.cc | 2 +- snapshot/minidump/exception_snapshot_minidump.cc | 2 +- snapshot/minidump/exception_snapshot_minidump.h | 2 +- snapshot/minidump/memory_snapshot_minidump.cc | 2 +- snapshot/minidump/memory_snapshot_minidump.h | 2 +- snapshot/minidump/minidump_annotation_reader.cc | 2 +- snapshot/minidump/minidump_annotation_reader.h | 2 +- snapshot/minidump/minidump_context_converter.cc | 2 +- snapshot/minidump/minidump_context_converter.h | 2 +- snapshot/minidump/minidump_simple_string_dictionary_reader.cc | 2 +- snapshot/minidump/minidump_simple_string_dictionary_reader.h | 2 +- snapshot/minidump/minidump_stream.h | 2 +- snapshot/minidump/minidump_string_list_reader.cc | 2 +- snapshot/minidump/minidump_string_list_reader.h | 2 +- snapshot/minidump/minidump_string_reader.cc | 2 +- snapshot/minidump/minidump_string_reader.h | 2 +- snapshot/minidump/module_snapshot_minidump.cc | 2 +- snapshot/minidump/module_snapshot_minidump.h | 2 +- snapshot/minidump/process_snapshot_minidump.cc | 2 +- snapshot/minidump/process_snapshot_minidump.h | 2 +- snapshot/minidump/process_snapshot_minidump_test.cc | 2 +- snapshot/minidump/system_snapshot_minidump.cc | 2 +- snapshot/minidump/system_snapshot_minidump.h | 2 +- snapshot/minidump/thread_snapshot_minidump.cc | 2 +- snapshot/minidump/thread_snapshot_minidump.h | 2 +- snapshot/module_snapshot.h | 2 +- snapshot/posix/timezone.cc | 2 +- snapshot/posix/timezone.h | 2 +- snapshot/posix/timezone_test.cc | 2 +- snapshot/process_snapshot.h | 2 +- snapshot/sanitized/memory_snapshot_sanitized.cc | 2 +- snapshot/sanitized/memory_snapshot_sanitized.h | 2 +- snapshot/sanitized/module_snapshot_sanitized.cc | 2 +- snapshot/sanitized/module_snapshot_sanitized.h | 2 +- snapshot/sanitized/process_snapshot_sanitized.cc | 2 +- snapshot/sanitized/process_snapshot_sanitized.h | 2 +- snapshot/sanitized/process_snapshot_sanitized_test.cc | 2 +- snapshot/sanitized/sanitization_information.cc | 2 +- snapshot/sanitized/sanitization_information.h | 2 +- snapshot/sanitized/sanitization_information_test.cc | 2 +- snapshot/sanitized/thread_snapshot_sanitized.cc | 2 +- snapshot/sanitized/thread_snapshot_sanitized.h | 2 +- snapshot/snapshot_constants.h | 2 +- snapshot/system_snapshot.h | 2 +- snapshot/test/test_cpu_context.cc | 2 +- snapshot/test/test_cpu_context.h | 2 +- snapshot/test/test_exception_snapshot.cc | 2 +- snapshot/test/test_exception_snapshot.h | 2 +- snapshot/test/test_memory_map_region_snapshot.cc | 2 +- snapshot/test/test_memory_map_region_snapshot.h | 2 +- snapshot/test/test_memory_snapshot.cc | 2 +- snapshot/test/test_memory_snapshot.h | 2 +- snapshot/test/test_module_snapshot.cc | 2 +- snapshot/test/test_module_snapshot.h | 2 +- snapshot/test/test_process_snapshot.cc | 2 +- snapshot/test/test_process_snapshot.h | 2 +- snapshot/test/test_system_snapshot.cc | 2 +- snapshot/test/test_system_snapshot.h | 2 +- snapshot/test/test_thread_snapshot.cc | 2 +- snapshot/test/test_thread_snapshot.h | 2 +- snapshot/thread_snapshot.h | 2 +- snapshot/unloaded_module_snapshot.cc | 2 +- snapshot/unloaded_module_snapshot.h | 2 +- snapshot/win/capture_memory_delegate_win.cc | 2 +- snapshot/win/capture_memory_delegate_win.h | 2 +- snapshot/win/cpu_context_win.cc | 2 +- snapshot/win/cpu_context_win.h | 2 +- snapshot/win/cpu_context_win_test.cc | 2 +- snapshot/win/crashpad_snapshot_test_annotations.cc | 2 +- snapshot/win/crashpad_snapshot_test_crashing_child.cc | 2 +- snapshot/win/crashpad_snapshot_test_dump_without_crashing.cc | 2 +- snapshot/win/crashpad_snapshot_test_extra_memory_ranges.cc | 2 +- snapshot/win/crashpad_snapshot_test_image_reader.cc | 2 +- snapshot/win/crashpad_snapshot_test_image_reader_module.cc | 2 +- snapshot/win/end_to_end_test.py | 2 +- snapshot/win/exception_snapshot_win.cc | 2 +- snapshot/win/exception_snapshot_win.h | 2 +- snapshot/win/exception_snapshot_win_test.cc | 2 +- snapshot/win/extra_memory_ranges_test.cc | 2 +- snapshot/win/memory_map_region_snapshot_win.cc | 2 +- snapshot/win/memory_map_region_snapshot_win.h | 2 +- snapshot/win/module_snapshot_win.cc | 2 +- snapshot/win/module_snapshot_win.h | 2 +- snapshot/win/module_snapshot_win_test.cc | 2 +- snapshot/win/pe_image_annotations_reader.cc | 2 +- snapshot/win/pe_image_annotations_reader.h | 2 +- snapshot/win/pe_image_reader.cc | 2 +- snapshot/win/pe_image_reader.h | 2 +- snapshot/win/pe_image_reader_test.cc | 2 +- snapshot/win/pe_image_resource_reader.cc | 2 +- snapshot/win/pe_image_resource_reader.h | 2 +- snapshot/win/process_reader_win.cc | 2 +- snapshot/win/process_reader_win.h | 2 +- snapshot/win/process_reader_win_test.cc | 2 +- snapshot/win/process_snapshot_win.cc | 2 +- snapshot/win/process_snapshot_win.h | 2 +- snapshot/win/process_snapshot_win_test.cc | 2 +- snapshot/win/process_subrange_reader.cc | 2 +- snapshot/win/process_subrange_reader.h | 2 +- snapshot/win/system_snapshot_win.cc | 2 +- snapshot/win/system_snapshot_win.h | 2 +- snapshot/win/system_snapshot_win_test.cc | 2 +- snapshot/win/thread_snapshot_win.cc | 2 +- snapshot/win/thread_snapshot_win.h | 2 +- snapshot/x86/cpuid_reader.cc | 2 +- snapshot/x86/cpuid_reader.h | 2 +- test/BUILD.gn | 2 +- test/errors.cc | 2 +- test/errors.h | 2 +- test/file.cc | 2 +- test/file.h | 2 +- test/filesystem.cc | 2 +- test/filesystem.h | 2 +- test/gtest_death.h | 2 +- test/gtest_main.cc | 2 +- test/hex_string.cc | 2 +- test/hex_string.h | 2 +- test/hex_string_test.cc | 2 +- test/ios/BUILD.gn | 2 +- test/ios/cptest_google_test_runner.mm | 2 +- test/ios/cptest_google_test_runner_delegate.h | 2 +- test/ios/crash_type_xctest.mm | 2 +- test/ios/google_test_setup.h | 2 +- test/ios/google_test_setup.mm | 2 +- test/ios/host/BUILD.gn | 2 +- test/ios/host/cptest_application_delegate.h | 2 +- test/ios/host/cptest_application_delegate.mm | 2 +- test/ios/host/cptest_crash_view_controller.h | 2 +- test/ios/host/cptest_crash_view_controller.mm | 2 +- test/ios/host/cptest_shared_object.h | 2 +- test/ios/host/handler_forbidden_allocators.cc | 2 +- test/ios/host/handler_forbidden_allocators.h | 2 +- test/ios/host/main.mm | 2 +- test/linux/fake_ptrace_connection.cc | 2 +- test/linux/fake_ptrace_connection.h | 2 +- test/linux/get_tls.cc | 2 +- test/linux/get_tls.h | 2 +- test/mac/dyld.cc | 2 +- test/mac/dyld.h | 2 +- test/mac/exception_swallower.cc | 2 +- test/mac/exception_swallower.h | 2 +- test/mac/mach_errors.cc | 2 +- test/mac/mach_errors.h | 2 +- test/mac/mach_multiprocess.cc | 2 +- test/mac/mach_multiprocess.h | 2 +- test/mac/mach_multiprocess_test.cc | 2 +- test/main_arguments.cc | 2 +- test/main_arguments.h | 2 +- test/main_arguments_test.cc | 2 +- test/multiprocess.h | 2 +- test/multiprocess_exec.cc | 2 +- test/multiprocess_exec.h | 2 +- test/multiprocess_exec_fuchsia.cc | 2 +- test/multiprocess_exec_posix.cc | 2 +- test/multiprocess_exec_test.cc | 2 +- test/multiprocess_exec_test_child.cc | 2 +- test/multiprocess_exec_win.cc | 2 +- test/multiprocess_posix.cc | 2 +- test/multiprocess_posix_test.cc | 2 +- test/process_type.cc | 2 +- test/process_type.h | 2 +- test/scoped_guarded_page.h | 2 +- test/scoped_guarded_page_posix.cc | 2 +- test/scoped_guarded_page_test.cc | 2 +- test/scoped_guarded_page_win.cc | 2 +- test/scoped_module_handle.cc | 2 +- test/scoped_module_handle.h | 2 +- test/scoped_set_thread_name.h | 2 +- test/scoped_set_thread_name_fuchsia.cc | 2 +- test/scoped_set_thread_name_posix.cc | 2 +- test/scoped_set_thread_name_win.cc | 2 +- test/scoped_temp_dir.cc | 2 +- test/scoped_temp_dir.h | 2 +- test/scoped_temp_dir_posix.cc | 2 +- test/scoped_temp_dir_test.cc | 2 +- test/scoped_temp_dir_win.cc | 2 +- test/test_paths.cc | 2 +- test/test_paths.h | 2 +- test/test_paths_test.cc | 2 +- test/test_paths_test_data_root.txt | 2 +- test/win/child_launcher.cc | 2 +- test/win/child_launcher.h | 2 +- test/win/win_child_process.cc | 2 +- test/win/win_child_process.h | 2 +- test/win/win_child_process_test.cc | 2 +- test/win/win_multiprocess.cc | 2 +- test/win/win_multiprocess.h | 2 +- test/win/win_multiprocess_test.cc | 2 +- test/win/win_multiprocess_with_temp_dir.cc | 2 +- test/win/win_multiprocess_with_temp_dir.h | 2 +- third_party/cpp-httplib/BUILD.gn | 2 +- third_party/fuchsia/BUILD.gn | 2 +- third_party/fuchsia/runner.py | 2 +- third_party/getopt/BUILD.gn | 2 +- third_party/googletest/BUILD.gn | 2 +- third_party/libfuzzer/BUILD.gn | 2 +- third_party/lss/BUILD.gn | 2 +- third_party/lss/lss.h | 2 +- third_party/mini_chromium/BUILD.gn | 2 +- third_party/xnu/BUILD.gn | 2 +- third_party/zlib/BUILD.gn | 2 +- third_party/zlib/zlib_crashpad.h | 2 +- tools/BUILD.gn | 2 +- tools/base94_encoder.cc | 2 +- tools/base94_encoder.md | 2 +- tools/crashpad_database_util.cc | 2 +- tools/crashpad_database_util.md | 2 +- tools/crashpad_http_upload.cc | 2 +- tools/crashpad_http_upload.md | 2 +- tools/generate_dump.cc | 2 +- tools/generate_dump.md | 2 +- tools/mac/catch_exception_tool.cc | 2 +- tools/mac/catch_exception_tool.md | 2 +- tools/mac/exception_port_tool.cc | 2 +- tools/mac/exception_port_tool.md | 2 +- tools/mac/on_demand_service_tool.md | 2 +- tools/mac/on_demand_service_tool.mm | 2 +- tools/run_with_crashpad.cc | 2 +- tools/run_with_crashpad.md | 2 +- tools/tool_support.cc | 2 +- tools/tool_support.h | 2 +- util/BUILD.gn | 2 +- util/file/delimited_file_reader.cc | 2 +- util/file/delimited_file_reader.h | 2 +- util/file/delimited_file_reader_test.cc | 2 +- util/file/directory_reader.h | 2 +- util/file/directory_reader_posix.cc | 2 +- util/file/directory_reader_test.cc | 2 +- util/file/directory_reader_win.cc | 2 +- util/file/file_helper.cc | 2 +- util/file/file_helper.h | 2 +- util/file/file_io.cc | 2 +- util/file/file_io.h | 2 +- util/file/file_io_posix.cc | 2 +- util/file/file_io_test.cc | 2 +- util/file/file_io_win.cc | 2 +- util/file/file_reader.cc | 2 +- util/file/file_reader.h | 2 +- util/file/file_reader_test.cc | 2 +- util/file/file_seeker.cc | 2 +- util/file/file_seeker.h | 2 +- util/file/file_writer.cc | 2 +- util/file/file_writer.h | 2 +- util/file/filesystem.h | 2 +- util/file/filesystem_posix.cc | 2 +- util/file/filesystem_test.cc | 2 +- util/file/filesystem_win.cc | 2 +- util/file/output_stream_file_writer.cc | 2 +- util/file/output_stream_file_writer.h | 2 +- util/file/scoped_remove_file.cc | 2 +- util/file/scoped_remove_file.h | 2 +- util/file/string_file.cc | 2 +- util/file/string_file.h | 2 +- util/file/string_file_test.cc | 2 +- util/fuchsia/koid_utilities.cc | 2 +- util/fuchsia/koid_utilities.h | 2 +- util/fuchsia/scoped_task_suspend.cc | 2 +- util/fuchsia/scoped_task_suspend.h | 2 +- util/fuchsia/traits.h | 2 +- util/ios/ios_intermediate_dump_data.cc | 2 +- util/ios/ios_intermediate_dump_data.h | 2 +- util/ios/ios_intermediate_dump_format.h | 2 +- util/ios/ios_intermediate_dump_interface.cc | 2 +- util/ios/ios_intermediate_dump_interface.h | 2 +- util/ios/ios_intermediate_dump_list.cc | 2 +- util/ios/ios_intermediate_dump_list.h | 2 +- util/ios/ios_intermediate_dump_map.cc | 2 +- util/ios/ios_intermediate_dump_map.h | 2 +- util/ios/ios_intermediate_dump_object.cc | 2 +- util/ios/ios_intermediate_dump_object.h | 2 +- util/ios/ios_intermediate_dump_reader.cc | 2 +- util/ios/ios_intermediate_dump_reader.h | 2 +- util/ios/ios_intermediate_dump_reader_test.cc | 2 +- util/ios/ios_intermediate_dump_writer.cc | 2 +- util/ios/ios_intermediate_dump_writer.h | 2 +- util/ios/ios_intermediate_dump_writer_test.cc | 2 +- util/ios/ios_system_data_collector.h | 2 +- util/ios/ios_system_data_collector.mm | 2 +- util/ios/raw_logging.cc | 2 +- util/ios/raw_logging.h | 2 +- util/ios/scoped_background_task.mm | 2 +- util/ios/scoped_vm_read.cc | 2 +- util/ios/scoped_vm_read.h | 2 +- util/ios/scoped_vm_read_test.cc | 2 +- util/linux/address_types.h | 2 +- util/linux/auxiliary_vector.cc | 2 +- util/linux/auxiliary_vector.h | 2 +- util/linux/auxiliary_vector_test.cc | 2 +- util/linux/checked_linux_address_range.h | 2 +- util/linux/direct_ptrace_connection.cc | 2 +- util/linux/direct_ptrace_connection.h | 2 +- util/linux/exception_handler_client.cc | 2 +- util/linux/exception_handler_client.h | 2 +- util/linux/exception_handler_protocol.cc | 2 +- util/linux/exception_handler_protocol.h | 2 +- util/linux/exception_information.h | 2 +- util/linux/initial_signal_dispositions.cc | 2 +- util/linux/initial_signal_dispositions.h | 2 +- util/linux/memory_map.cc | 2 +- util/linux/memory_map.h | 2 +- util/linux/memory_map_test.cc | 2 +- util/linux/proc_stat_reader.cc | 2 +- util/linux/proc_stat_reader.h | 2 +- util/linux/proc_stat_reader_test.cc | 2 +- util/linux/proc_task_reader.cc | 2 +- util/linux/proc_task_reader.h | 2 +- util/linux/proc_task_reader_test.cc | 2 +- util/linux/ptrace_broker.cc | 2 +- util/linux/ptrace_broker.h | 2 +- util/linux/ptrace_broker_test.cc | 2 +- util/linux/ptrace_client.cc | 2 +- util/linux/ptrace_client.h | 2 +- util/linux/ptrace_connection.h | 2 +- util/linux/ptracer.cc | 2 +- util/linux/ptracer.h | 2 +- util/linux/ptracer_test.cc | 2 +- util/linux/scoped_pr_set_dumpable.cc | 2 +- util/linux/scoped_pr_set_dumpable.h | 2 +- util/linux/scoped_pr_set_ptracer.cc | 2 +- util/linux/scoped_pr_set_ptracer.h | 2 +- util/linux/scoped_ptrace_attach.cc | 2 +- util/linux/scoped_ptrace_attach.h | 2 +- util/linux/scoped_ptrace_attach_test.cc | 2 +- util/linux/socket.cc | 2 +- util/linux/socket.h | 2 +- util/linux/socket_test.cc | 2 +- util/linux/thread_info.cc | 2 +- util/linux/thread_info.h | 2 +- util/linux/traits.h | 2 +- util/mac/checked_mach_address_range.h | 2 +- util/mac/checked_mach_address_range_test.cc | 2 +- util/mac/launchd.h | 2 +- util/mac/launchd.mm | 2 +- util/mac/launchd_test.mm | 2 +- util/mac/mac_util.cc | 2 +- util/mac/mac_util.h | 2 +- util/mac/mac_util_test.mm | 2 +- util/mac/service_management.cc | 2 +- util/mac/service_management.h | 2 +- util/mac/service_management_test.mm | 2 +- util/mac/sysctl.cc | 2 +- util/mac/sysctl.h | 2 +- util/mac/sysctl_test.cc | 2 +- util/mac/xattr.cc | 2 +- util/mac/xattr.h | 2 +- util/mac/xattr_test.cc | 2 +- util/mach/bootstrap.cc | 2 +- util/mach/bootstrap.h | 2 +- util/mach/bootstrap_test.cc | 2 +- util/mach/child_port.defs | 2 +- util/mach/child_port_handshake.cc | 2 +- util/mach/child_port_handshake.h | 2 +- util/mach/child_port_handshake_test.cc | 2 +- util/mach/child_port_server.cc | 2 +- util/mach/child_port_server.h | 2 +- util/mach/child_port_server_test.cc | 2 +- util/mach/child_port_types.h | 2 +- util/mach/composite_mach_message_server.cc | 2 +- util/mach/composite_mach_message_server.h | 2 +- util/mach/composite_mach_message_server_test.cc | 2 +- util/mach/exc_client_variants.cc | 2 +- util/mach/exc_client_variants.h | 2 +- util/mach/exc_client_variants_test.cc | 2 +- util/mach/exc_server_variants.cc | 2 +- util/mach/exc_server_variants.h | 2 +- util/mach/exc_server_variants_test.cc | 2 +- util/mach/exception_behaviors.cc | 2 +- util/mach/exception_behaviors.h | 2 +- util/mach/exception_behaviors_test.cc | 2 +- util/mach/exception_ports.cc | 2 +- util/mach/exception_ports.h | 2 +- util/mach/exception_ports_test.cc | 2 +- util/mach/exception_types.cc | 2 +- util/mach/exception_types.h | 2 +- util/mach/exception_types_test.cc | 2 +- util/mach/mach_extensions.cc | 2 +- util/mach/mach_extensions.h | 2 +- util/mach/mach_extensions_test.cc | 2 +- util/mach/mach_message.cc | 2 +- util/mach/mach_message.h | 2 +- util/mach/mach_message_server.cc | 2 +- util/mach/mach_message_server.h | 2 +- util/mach/mach_message_server_test.cc | 2 +- util/mach/mach_message_test.cc | 2 +- util/mach/mig.py | 2 +- util/mach/mig_fix.py | 2 +- util/mach/mig_gen.py | 2 +- util/mach/notify_server.cc | 2 +- util/mach/notify_server.h | 2 +- util/mach/notify_server_test.cc | 2 +- util/mach/scoped_task_suspend.cc | 2 +- util/mach/scoped_task_suspend.h | 2 +- util/mach/scoped_task_suspend_test.cc | 2 +- util/mach/symbolic_constants_mach.cc | 2 +- util/mach/symbolic_constants_mach.h | 2 +- util/mach/symbolic_constants_mach_test.cc | 2 +- util/mach/task_for_pid.cc | 2 +- util/mach/task_for_pid.h | 2 +- util/misc/address_sanitizer.h | 2 +- util/misc/address_types.h | 2 +- util/misc/arm64_pac_bti.S | 2 +- util/misc/arraysize.h | 2 +- util/misc/arraysize_test.cc | 2 +- util/misc/as_underlying_type.h | 2 +- util/misc/capture_context.h | 2 +- util/misc/capture_context_fuchsia.S | 2 +- util/misc/capture_context_linux.S | 2 +- util/misc/capture_context_mac.S | 2 +- util/misc/capture_context_test.cc | 2 +- util/misc/capture_context_test_util.h | 2 +- util/misc/capture_context_test_util_fuchsia.cc | 2 +- util/misc/capture_context_test_util_linux.cc | 2 +- util/misc/capture_context_test_util_mac.cc | 2 +- util/misc/capture_context_test_util_win.cc | 2 +- util/misc/capture_context_win.asm | 2 +- util/misc/capture_context_win_arm64.asm | 2 +- util/misc/clock.h | 2 +- util/misc/clock_mac.cc | 2 +- util/misc/clock_posix.cc | 2 +- util/misc/clock_test.cc | 2 +- util/misc/clock_win.cc | 2 +- util/misc/elf_note_types.h | 2 +- util/misc/from_pointer_cast.h | 2 +- util/misc/from_pointer_cast_test.cc | 2 +- util/misc/implicit_cast.h | 2 +- util/misc/initialization_state.h | 2 +- util/misc/initialization_state_dcheck.cc | 2 +- util/misc/initialization_state_dcheck.h | 2 +- util/misc/initialization_state_dcheck_test.cc | 2 +- util/misc/initialization_state_test.cc | 2 +- util/misc/lexing.cc | 2 +- util/misc/lexing.h | 2 +- util/misc/memory_sanitizer.h | 2 +- util/misc/metrics.cc | 2 +- util/misc/metrics.h | 2 +- util/misc/no_cfi_icall.h | 2 +- util/misc/no_cfi_icall_test.cc | 2 +- util/misc/paths.h | 2 +- util/misc/paths_fuchsia.cc | 2 +- util/misc/paths_linux.cc | 2 +- util/misc/paths_mac.cc | 2 +- util/misc/paths_test.cc | 2 +- util/misc/paths_win.cc | 2 +- util/misc/pdb_structures.cc | 2 +- util/misc/pdb_structures.h | 2 +- util/misc/random_string.cc | 2 +- util/misc/random_string.h | 2 +- util/misc/random_string_test.cc | 2 +- util/misc/range_set.cc | 2 +- util/misc/range_set.h | 2 +- util/misc/range_set_test.cc | 2 +- util/misc/reinterpret_bytes.cc | 2 +- util/misc/reinterpret_bytes.h | 2 +- util/misc/reinterpret_bytes_test.cc | 2 +- util/misc/scoped_forbid_return.cc | 2 +- util/misc/scoped_forbid_return.h | 2 +- util/misc/scoped_forbid_return_test.cc | 2 +- util/misc/symbolic_constants_common.h | 2 +- util/misc/time.cc | 2 +- util/misc/time.h | 2 +- util/misc/time_linux.cc | 2 +- util/misc/time_test.cc | 2 +- util/misc/time_win.cc | 2 +- util/misc/tri_state.h | 2 +- util/misc/uuid.cc | 2 +- util/misc/uuid.h | 2 +- util/misc/uuid_test.cc | 2 +- util/misc/zlib.cc | 2 +- util/misc/zlib.h | 2 +- util/net/generate_test_server_key.py | 2 +- util/net/http_body.cc | 2 +- util/net/http_body.h | 2 +- util/net/http_body_gzip.cc | 2 +- util/net/http_body_gzip.h | 2 +- util/net/http_body_gzip_test.cc | 2 +- util/net/http_body_test.cc | 2 +- util/net/http_body_test_util.cc | 2 +- util/net/http_body_test_util.h | 2 +- util/net/http_headers.h | 2 +- util/net/http_multipart_builder.cc | 2 +- util/net/http_multipart_builder.h | 2 +- util/net/http_multipart_builder_test.cc | 2 +- util/net/http_transport.cc | 2 +- util/net/http_transport.h | 2 +- util/net/http_transport_libcurl.cc | 2 +- util/net/http_transport_mac.mm | 2 +- util/net/http_transport_socket.cc | 2 +- util/net/http_transport_test.cc | 2 +- util/net/http_transport_test_server.cc | 2 +- util/net/http_transport_win.cc | 2 +- util/net/tls.gni | 2 +- util/net/url.cc | 2 +- util/net/url.h | 2 +- util/net/url_test.cc | 2 +- util/numeric/checked_address_range.cc | 2 +- util/numeric/checked_address_range.h | 2 +- util/numeric/checked_address_range_test.cc | 2 +- util/numeric/checked_range.h | 2 +- util/numeric/checked_range_test.cc | 2 +- util/numeric/checked_vm_address_range.h | 2 +- util/numeric/in_range_cast.h | 2 +- util/numeric/in_range_cast_test.cc | 2 +- util/numeric/int128.h | 2 +- util/numeric/int128_test.cc | 2 +- util/numeric/safe_assignment.h | 2 +- util/posix/close_multiple.cc | 2 +- util/posix/close_multiple.h | 2 +- util/posix/close_stdio.cc | 2 +- util/posix/close_stdio.h | 2 +- util/posix/drop_privileges.cc | 2 +- util/posix/drop_privileges.h | 2 +- util/posix/process_info.h | 2 +- util/posix/process_info_linux.cc | 2 +- util/posix/process_info_mac.cc | 2 +- util/posix/process_info_test.cc | 2 +- util/posix/scoped_dir.cc | 2 +- util/posix/scoped_dir.h | 2 +- util/posix/scoped_mmap.cc | 2 +- util/posix/scoped_mmap.h | 2 +- util/posix/scoped_mmap_test.cc | 2 +- util/posix/signals.cc | 2 +- util/posix/signals.h | 2 +- util/posix/signals_test.cc | 2 +- util/posix/spawn_subprocess.cc | 2 +- util/posix/spawn_subprocess.h | 2 +- util/posix/symbolic_constants_posix.cc | 2 +- util/posix/symbolic_constants_posix.h | 2 +- util/posix/symbolic_constants_posix_test.cc | 2 +- util/process/process_id.h | 2 +- util/process/process_memory.cc | 2 +- util/process/process_memory.h | 2 +- util/process/process_memory_fuchsia.cc | 2 +- util/process/process_memory_fuchsia.h | 2 +- util/process/process_memory_linux.cc | 2 +- util/process/process_memory_linux.h | 2 +- util/process/process_memory_mac.cc | 2 +- util/process/process_memory_mac.h | 2 +- util/process/process_memory_mac_test.cc | 2 +- util/process/process_memory_native.h | 2 +- util/process/process_memory_range.cc | 2 +- util/process/process_memory_range.h | 2 +- util/process/process_memory_range_test.cc | 2 +- util/process/process_memory_sanitized.cc | 2 +- util/process/process_memory_sanitized.h | 2 +- util/process/process_memory_sanitized_test.cc | 2 +- util/process/process_memory_test.cc | 2 +- util/process/process_memory_win.cc | 2 +- util/process/process_memory_win.h | 2 +- util/stdlib/aligned_allocator.cc | 2 +- util/stdlib/aligned_allocator.h | 2 +- util/stdlib/aligned_allocator_test.cc | 2 +- util/stdlib/map_insert.h | 2 +- util/stdlib/map_insert_test.cc | 2 +- util/stdlib/objc.h | 2 +- util/stdlib/string_number_conversion.cc | 2 +- util/stdlib/string_number_conversion.h | 2 +- util/stdlib/string_number_conversion_test.cc | 2 +- util/stdlib/strlcpy.cc | 2 +- util/stdlib/strlcpy.h | 2 +- util/stdlib/strlcpy_test.cc | 2 +- util/stdlib/strnlen.cc | 2 +- util/stdlib/strnlen.h | 2 +- util/stdlib/strnlen_test.cc | 2 +- util/stdlib/thread_safe_vector.h | 2 +- util/stdlib/thread_safe_vector_test.cc | 2 +- util/stream/base94_output_stream.cc | 2 +- util/stream/base94_output_stream.h | 2 +- util/stream/base94_output_stream_test.cc | 2 +- util/stream/file_encoder.cc | 2 +- util/stream/file_encoder.h | 2 +- util/stream/file_encoder_test.cc | 2 +- util/stream/file_output_stream.cc | 2 +- util/stream/file_output_stream.h | 2 +- util/stream/log_output_stream.cc | 2 +- util/stream/log_output_stream.h | 2 +- util/stream/log_output_stream_test.cc | 2 +- util/stream/output_stream_interface.h | 2 +- util/stream/test_output_stream.cc | 2 +- util/stream/test_output_stream.h | 2 +- util/stream/zlib_output_stream.cc | 2 +- util/stream/zlib_output_stream.h | 2 +- util/stream/zlib_output_stream_test.cc | 2 +- util/string/split_string.cc | 2 +- util/string/split_string.h | 2 +- util/string/split_string_test.cc | 2 +- util/synchronization/semaphore.h | 2 +- util/synchronization/semaphore_mac.cc | 2 +- util/synchronization/semaphore_posix.cc | 2 +- util/synchronization/semaphore_test.cc | 2 +- util/synchronization/semaphore_win.cc | 2 +- util/thread/stoppable.h | 2 +- util/thread/thread.cc | 2 +- util/thread/thread.h | 2 +- util/thread/thread_log_messages.cc | 2 +- util/thread/thread_log_messages.h | 2 +- util/thread/thread_log_messages_test.cc | 2 +- util/thread/thread_posix.cc | 2 +- util/thread/thread_test.cc | 2 +- util/thread/thread_win.cc | 2 +- util/thread/worker_thread.cc | 2 +- util/thread/worker_thread.h | 2 +- util/thread/worker_thread_test.cc | 2 +- util/win/address_types.h | 2 +- util/win/checked_win_address_range.h | 2 +- util/win/command_line.cc | 2 +- util/win/command_line.h | 2 +- util/win/command_line_test.cc | 2 +- util/win/context_wrappers.h | 2 +- util/win/critical_section_with_debug_info.cc | 2 +- util/win/critical_section_with_debug_info.h | 2 +- util/win/critical_section_with_debug_info_test.cc | 2 +- util/win/exception_codes.h | 2 +- util/win/exception_handler_server.cc | 2 +- util/win/exception_handler_server.h | 2 +- util/win/exception_handler_server_test.cc | 2 +- util/win/get_function.cc | 2 +- util/win/get_function.h | 2 +- util/win/get_function_test.cc | 2 +- util/win/get_module_information.cc | 2 +- util/win/get_module_information.h | 2 +- util/win/handle.cc | 2 +- util/win/handle.h | 2 +- util/win/handle_test.cc | 2 +- util/win/initial_client_data.cc | 2 +- util/win/initial_client_data.h | 2 +- util/win/initial_client_data_test.cc | 2 +- util/win/loader_lock.cc | 2 +- util/win/loader_lock.h | 2 +- util/win/loader_lock_test.cc | 2 +- util/win/loader_lock_test_dll.cc | 2 +- util/win/module_version.cc | 2 +- util/win/module_version.h | 2 +- util/win/nt_internals.cc | 2 +- util/win/nt_internals.h | 2 +- util/win/ntstatus_logging.cc | 2 +- util/win/ntstatus_logging.h | 2 +- util/win/process_info.cc | 2 +- util/win/process_info.h | 2 +- util/win/process_info_test.cc | 2 +- util/win/process_info_test_child.cc | 2 +- util/win/process_structs.h | 2 +- util/win/registration_protocol_win.cc | 2 +- util/win/registration_protocol_win.h | 2 +- util/win/registration_protocol_win_structs.h | 2 +- util/win/registration_protocol_win_test.cc | 2 +- util/win/safe_terminate_process.asm | 2 +- util/win/safe_terminate_process.h | 2 +- util/win/safe_terminate_process_test.cc | 2 +- util/win/safe_terminate_process_test_child.cc | 2 +- util/win/scoped_handle.cc | 2 +- util/win/scoped_handle.h | 2 +- util/win/scoped_local_alloc.cc | 2 +- util/win/scoped_local_alloc.h | 2 +- util/win/scoped_process_suspend.cc | 2 +- util/win/scoped_process_suspend.h | 2 +- util/win/scoped_process_suspend_test.cc | 2 +- util/win/scoped_registry_key.h | 2 +- util/win/scoped_set_event.cc | 2 +- util/win/scoped_set_event.h | 2 +- util/win/session_end_watcher.cc | 2 +- util/win/session_end_watcher.h | 2 +- util/win/session_end_watcher_test.cc | 2 +- util/win/termination_codes.h | 2 +- util/win/traits.h | 2 +- util/win/xp_compat.h | 2 +- 1097 files changed, 1098 insertions(+), 1098 deletions(-) diff --git a/.clang-format b/.clang-format index 0be5323f5b..8508426fe6 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,4 @@ -# Copyright 2014 The Crashpad Authors. All rights reserved. +# Copyright 2014 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.gitattributes b/.gitattributes index 9bfc20d15c..644b9e2573 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,4 @@ -# Copyright 2019 The Crashpad Authors. All rights reserved. +# Copyright 2019 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.gitignore b/.gitignore index b739477a52..4de7d077c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Copyright 2014 The Crashpad Authors. All rights reserved. +# Copyright 2014 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.gn b/.gn index e4dc49c31f..f2db1da269 100644 --- a/.gn +++ b/.gn @@ -1,4 +1,4 @@ -# Copyright 2017 The Crashpad Authors. All rights reserved. +# Copyright 2017 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.style.yapf b/.style.yapf index 8aaf9b62c7..1471bc8225 100644 --- a/.style.yapf +++ b/.style.yapf @@ -1,4 +1,4 @@ -# Copyright 2020 The Crashpad Authors. All rights reserved. +# Copyright 2020 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.vpython b/.vpython index c2001fc5df..3086f5d14d 100644 --- a/.vpython +++ b/.vpython @@ -1,4 +1,4 @@ -# Copyright 2018 The Crashpad Authors. All rights reserved. +# Copyright 2018 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.vpython3 b/.vpython3 index 0d7baf9efc..f16930379f 100644 --- a/.vpython3 +++ b/.vpython3 @@ -1,4 +1,4 @@ -# Copyright 2022 The Crashpad Authors. All rights reserved. +# Copyright 2022 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/BUILD.gn b/BUILD.gn index c782b9b9cc..a2d92e62a5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright 2017 The Crashpad Authors. All rights reserved. +# Copyright 2017 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/DEPS b/DEPS index 0f29f6d024..cd9ee99f7c 100644 --- a/DEPS +++ b/DEPS @@ -1,4 +1,4 @@ -# Copyright 2014 The Crashpad Authors. All rights reserved. +# Copyright 2014 The Crashpad Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ deps = { 'e1e7b0ad8ee99a875b272c8e33e308472e897660', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '75dcb8dc417af77fdb9ec23c7b51cb1d57dfcee2', + '4332ddb6963750e1106efdcece6d6e2de6dc6430', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/README.md b/README.md index b20777bbf8..1db2920e18 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@